@fluidframework/odsp-driver 2.0.5 → 2.0.6

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.
@@ -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":"AAAA;;;GAGG;AAGH,OAAO,EAGN,WAAW,EAEX,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAEN,MAAM,EACN,UAAU,EAIV,eAAe,EAKf,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EACN,mBAAmB,EAMnB,MAAM,0CAA0C,CAAC;AAKlD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EACN,aAAa,EAKb,MAAM,gBAAgB,CAAC;AAGxB;;GAEG;AACH,MAAM,MAAM,SAAS,GAClB,MAAM,GACN,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,KAAK,GACL,MAAM,GACN,cAAc,GACd,aAAa,GACb,eAAe,GACf,MAAM,GACN,UAAU,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,YAAa,YAAW,mBAAmB;IAStD,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,eAAe;IACzC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,UAAU;IACxC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB;IAC9C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IAXvC,OAAO,CAAC,WAAW,CAAqB;IAExC,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAS;IACtD,SAAgB,WAAW,EAAE,WAAW,CAAC;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IAEnC,OAAO,CAAC,iBAAiB,CAAK;gBAEV,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,mBAAmB,EAC3B,kBAAkB,CAAC,qBAAS;IAczC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAczE,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAiDhC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB7C,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3C,IAAW,UAAU,IAAI,MAAM,GAAG,SAAS,CAE1C;IAEY,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAU1F;;;;;;;OAOG;IACU,mBAAmB,CAAC,CAAC,EACjC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,WAAW,EACzB,SAAS,EAAE,SAAS,EACpB,SAAS,GAAE,OAAe,EAC1B,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAW5B;;;;;;;OAOG;IACU,KAAK,CACjB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,WAAW,EACzB,SAAS,EAAE,SAAS,EACpB,SAAS,GAAE,OAAe,EAC1B,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAWrB,SAAS;IA6DvB;;;;;;;OAOG;IACU,UAAU,CACtB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,EAC9C,SAAS,EAAE,SAAS,EACpB,SAAS,GAAE,OAAe,EAC1B,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAWtC,OAAO,CAAC,iBAAiB;IAqCzB,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,yBAAyB;IAajC,SAAS,CAAC,yBAAyB,CAClC,iBAAiB,EAAE,MAAM,GAAG,SAAS,EACrC,SAAS,EAAE,iBAAiB,EAC5B,SAAS,GAAE,OAAe,GACxB,IAAI;YAUO,kBAAkB;IA+BhC,OAAO,CAAC,sBAAsB;IAiB9B,OAAO,CAAC,kBAAkB;CAG1B;AAED,qBAAa,0BAA2B,SAAQ,YAAY;IAI1D,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,eAAe;IACzC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,UAAU;IACxC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB;IAC9C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IANvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAwB;gBAGxC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,mBAAmB,EAC3B,kBAAkB,CAAC,qBAAS;IAOhD,SAAS,CAAC,yBAAyB,CAClC,iBAAiB,EAAE,MAAM,GAAG,SAAS,EACrC,SAAS,EAAE,SAAS,EACpB,SAAS,GAAE,OAAe,GACxB,IAAI;IAWM,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAuBhC,mBAAmB,CAAC,CAAC,EACjC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,EAC9C,SAAS,EAAE,SAAS,EACpB,SAAS,GAAE,OAAe,EAC1B,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CAkE5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,wBAAgB,yBAAyB,CACxC,iBAAiB,EAAE,eAAe,EAClC,kBAAkB,EAAE,mBAAmB,EACvC,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,mBAAmB,EAC3B,kBAAkB,CAAC,EAAE,OAAO,GAC1B,gBAAgB,CAclB"}
@@ -82,7 +82,7 @@ class EpochTracker {
82
82
  }
83
83
  // Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately
84
84
  // expire all old caches that do not have cacheEntryTime
85
- if (entry.type === internal_3.snapshotKey) {
85
+ if (entry.type === internal_3.snapshotKey || entry.type === internal_3.snapshotWithLoadingGroupIdKey) {
86
86
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
87
87
  const cacheTime = value.value?.cacheEntryTime;
88
88
  const currentTime = Date.now();
@@ -111,7 +111,7 @@ class EpochTracker {
111
111
  (0, internal_1.assert)(this._fluidEpoch !== undefined, 0x1dd /* "no epoch" */);
112
112
  // For snapshots, the value should have the cacheEntryTime.
113
113
  // This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.
114
- if (entry.type === internal_3.snapshotKey) {
114
+ if (entry.type === internal_3.snapshotKey || entry.type === internal_3.snapshotWithLoadingGroupIdKey) {
115
115
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
116
116
  value.cacheEntryTime = value.cacheEntryTime ?? Date.now();
117
117
  }
@@ -359,7 +359,7 @@ class EpochTrackerWithRedemption extends EpochTracker {
359
359
  async get(entry) {
360
360
  let result = super.get(entry);
361
361
  // equivalence of what happens in fetchAndParseAsJSON()
362
- if (entry.type === internal_3.snapshotKey) {
362
+ if (entry.type === internal_3.snapshotKey || entry.type === internal_3.snapshotWithLoadingGroupIdKey) {
363
363
  result = result
364
364
  .then((value) => {
365
365
  // If there is nothing in cache, we need to wait for network call to complete (and do redemption)
@@ -1 +1 @@
1
- {"version":3,"file":"epochTracker.js","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,kEAAuE;AACvE,oEAK+C;AAC/C,+EAW0D;AAC1D,uEAOkD;AAClD,+BAAkC;AAElC,iDAAsF;AACtF,6DAA6D;AAE7D,6EAAoE;AACpE,iDAMwB;AACxB,2DAAkE;AAuBrD,QAAA,YAAY,GAAG,cAAc,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,MAAa,YAAY;IAQxB,YACoB,KAAsB,EACtB,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;QAH5B,UAAK,GAAL,KAAK,CAAiB;QACtB,cAAS,GAAT,SAAS,CAAY;QACrB,WAAM,GAAN,MAAM,CAAqB;QAC3B,uBAAkB,GAAlB,kBAAkB,CAAU;QAP/B,aAAQ,GAAG,IAAA,SAAI,GAAE,CAAC;QACnC,8DAA8D;QACtD,sBAAiB,GAAG,CAAC,CAAC;QAO7B,sDAAsD;QACtD,IAAI,CAAC,WAAW,GAAG,IAAI,sBAAW,CAAC,EAAE,CAAC,CAAC;QAEvC,6FAA6F;QAC7F,IAAI,CAAC,4BAA4B,GAAG,IAAA,oCAAyB,EAAC,MAAM,CAAC,CAAC,MAAM,CAAC,UAAU,CACtF,qDAAqD,CACrD;YACA,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,iCAAsB,CAAC;IAC3B,CAAC;IAED,+BAA+B;IACxB,QAAQ,CAAC,KAAa,EAAE,SAAkB,EAAE,SAA4B;QAC9E,IAAA,iBAAM,EAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAEzB,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAC9B,SAAS,EAAE,uBAAuB;YAClC,KAAK;YACL,SAAS;YACT,SAAS;SACT,CAAC,CAAC;IACJ,CAAC;IAED,+BAA+B;IAC/B,8DAA8D;IACvD,KAAK,CAAC,GAAG,CAAC,KAAa;QAC7B,IAAI,CAAC;YACJ,8FAA8F;YAC9F,mEAAmE;YACnE,MAAM,KAAK,GAA6B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAC3D,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAC9B,CAAC;YACF,0EAA0E;YAC1E,sCAAsC;YACtC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,yCAA0B,EAAE,CAAC;gBACzE,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,IAAA,iBAAM,EAAC,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACrF,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC/C,4FAA4F;gBAC5F,qCAAqC;YACtC,CAAC;iBAAM,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC;gBAClD,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,6FAA6F;YAC7F,wDAAwD;YACxD,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAW,EAAE,CAAC;gBAChC,+GAA+G;gBAC/G,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC;gBAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC/B,IACC,SAAS,KAAK,SAAS;oBACvB,WAAW,GAAG,SAAS,IAAI,IAAI,CAAC,4BAA4B,EAC3D,CAAC;oBACF,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;wBAC9B,SAAS,EAAE,0BAA0B;wBACrC,QAAQ,EAAE,WAAW,GAAG,SAAS;wBACjC,aAAa,EAAE,IAAI,CAAC,4BAA4B;qBAChD,CAAC,CAAC;oBACH,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC3B,OAAO,SAAS,CAAC;gBAClB,CAAC;YACF,CAAC;YACD,+DAA+D;YAC/D,OAAO,KAAK,CAAC,KAAK,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACtF,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IAED,0CAA0C;IAC1C,iHAAiH;IAC1G,KAAK,CAAC,GAAG,CAAC,KAAa,EAAE,KAAU;QACzC,IAAA,iBAAM,EAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC/D,2DAA2D;QAC3D,iFAAiF;QACjF,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAW,EAAE,CAAC;YAChC,+GAA+G;YAC/G,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3D,CAAC;QACD,MAAM,IAAI,GAA6B;YACtC,mEAAmE;YACnE,KAAK;YACL,OAAO,EAAE,yCAA0B;YACnC,UAAU,EAAE,IAAI,CAAC,WAAW;SAC5B,CAAC;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC3E,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACpF,MAAM,KAAK,CAAC;QACb,CAAC,CAAC,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,aAAa;QACzB,IAAI,CAAC;YACJ,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,EAAE,KAAK,CAAC,CAAC;QACxE,CAAC;IACF,CAAC;IAED,IAAW,UAAU;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,KAAyB,EAAE,SAAoB;QACzE,IAAA,iBAAM,EAAC,KAAK,KAAK,SAAS,EAAE,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvE,IAAI,CAAC;YACJ,IAAI,CAAC,yBAAyB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,mBAAmB,CAC/B,GAAW,EACX,YAAyB,EACzB,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,wCAAyB,EACzB,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,KAAK,CACjB,GAAW,EACX,YAAyB,EACzB,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,0BAAW,EACX,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS,CACtB,GAAW,EACX,YAAyB,EACzB,OAA8E,EAC9E,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,MAAM,mBAAmB,GAAG,IAAI,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC;QACxE,8BAA8B;QAC9B,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;QACrE,IAAI,iBAAqC,CAAC;QAC1C,OAAO,IAAI,CAAC,WAAW;aACrB,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;aAChD,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClB,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC1D,IAAI,CAAC,yBAAyB,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;YAC7D,QAAQ,CAAC,UAAU,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;YAC9D,OAAO,QAAQ,CAAC;QACjB,CAAC,CAAC;aACD,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACtB,4FAA4F;YAC5F,6BAA6B;YAC7B,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACrC,iBAAiB,GAAI,KAAoB,CAAC,WAAW,CAAC;YACvD,CAAC;YACD,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC;YACnE,MAAM,KAAK,CAAC;QACb,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,qGAAqG;YACrG,iBAAiB;YACjB,IACC,IAAA,uBAAY,EAAC,KAAK,CAAC;gBACnB,KAAK,CAAC,SAAS,KAAK,yBAAc,CAAC,+BAA+B,EACjE,CAAC;gBACF,MAAM,gBAAgB,GAAI,KAAiC,CAAC,gBAAgB,CAAC;gBAC7E,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;oBACpC,MAAM,WAAW,GAAqB,IAAA,iDAAoB,EACzD,IAAI,CAAC,SAAS,CAAC,WAAW,EAC1B,gBAAgB,CAChB,CAAC;oBACF,MAAM,wBAAwB,GAAG,IAAI,mCAAwB,CAC5D,KAAK,CAAC,OAAO,EACb,WAAW,EACX,EAAE,aAAa,EAAb,8BAAa,EAAE,gBAAgB,EAAE,CACnC,CAAC;oBACF,wBAAwB,CAAC,sBAAsB,CAAC,KAAK,CAAC,sBAAsB,EAAE,CAAC,CAAC;oBAChF,MAAM,wBAAwB,CAAC;gBAChC,CAAC;YACF,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,MAAM,UAAU,GAAG,IAAA,yBAAc,EAAC,KAAK,EAAE;gBACxC,KAAK,EAAE,EAAE,mBAAmB,EAAE,mBAAmB,EAAE;aACnD,CAAC,CAAC;YACH,MAAM,UAAU,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,UAAU,CACtB,GAAW,EACX,YAA8C,EAC9C,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,yBAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAEO,iBAAiB,CACxB,YAAyB,EACzB,SAAkB,EAClB,mBAA2B;QAE3B,MAAM,iBAAiB,GAAG,IAAA,iCAAkB,EAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,iBAAiB,CAAC;QAC3F,IAAI,SAAS,EAAE,CAAC;YACf,MAAM,OAAO,GAA8B,EAAE,CAAC;YAC9C,OAAO,CAAC,gBAAgB,CAAC,GAAG,mBAAmB,CAAC;YAChD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACnC,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC5C,CAAC;YACD,IAAI,iBAAiB,EAAE,CAAC;gBACvB,OAAO,CAAC,0CAAqB,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YACjF,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACP,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,GAAW,EAAQ,EAAE;gBACpD,YAAY,CAAC,OAAO,GAAG;oBACtB,GAAG,YAAY,CAAC,OAAO;iBACvB,CAAC;gBACF,IAAA,iBAAM,EACL,YAAY,CAAC,OAAO,KAAK,SAAS,EAClC,KAAK,CAAC,qCAAqC,CAC3C,CAAC;gBACF,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YACjC,CAAC,CAAC;YACF,SAAS,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACnC,SAAS,CAAC,eAAe,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7C,CAAC;YACD,IAAI,iBAAiB,EAAE,CAAC;gBACvB,SAAS,CAAC,0CAAqB,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC;YAClF,CAAC;QACF,CAAC;IACF,CAAC;IAEO,cAAc,CAAC,YAAyB,EAAE,OAAkC;QACnF,0EAA0E;QAC1E,wDAAwD;QACxD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;QAC/B,IAAA,iBAAM,EAAC,OAAO,IAAI,KAAK,QAAQ,EAAE,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACnE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;QACpC,IAAA,iBAAM,EAAC,SAAS,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACrF,MAAM,UAAU,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACpD,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC/B,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,YAAY,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAEO,yBAAyB,CAAC,WAAoB;QACrD,MAAM,KAAK,GAAa;YACvB,YAAY,IAAI,CAAC,QAAQ,EAAE;YAC3B,iBAAiB,IAAI,CAAC,iBAAiB,EAAE,EAAE;YAC3C,iBAAiB,8BAAa,EAAE;YAChC,gBAAgB,IAAI,CAAC,kBAAkB,EAAE;SACzC,CAAC;QACF,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,eAAe,WAAW,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAES,yBAAyB,CAClC,iBAAqC,EACrC,SAA4B,EAC5B,YAAqB,KAAK;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;QAC7D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,KAAK,CAAC;QACb,CAAC;QACD,IAAI,iBAAiB,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACvE,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACxD,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAC/B,KAAc,EACd,iBAA4C,EAC5C,SAA4B,EAC5B,YAAqB,KAAK;QAE1B,IAAI,IAAA,uBAAY,EAAC,KAAK,CAAC,IAAI,KAAK,CAAC,SAAS,KAAK,yBAAc,CAAC,wBAAwB,EAAE,CAAC;YACxF,MAAM,UAAU,GAAG,IAAI,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;YAClE,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC9B,UAAU,CAAC,sBAAsB,CAAC;oBACjC,SAAS;oBACT,SAAS;iBACT,CAAC,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,0BAA0B,EAAE,EAAE,UAAU,CAAC,CAAC;gBAClF,kFAAkF;gBAClF,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC3B,MAAM,UAAU,CAAC;YAClB,CAAC;YACD,wGAAwG;YACxG,0GAA0G;YAC1G,cAAc;YACd,MAAM,QAAQ,GAAG,IAAA,oBAAS,EAAC,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE;gBACrD,OAAO,IAAI,0BAAe,CAAC,kBAAkB,OAAO,EAAE,EAAE,CAAC,CAAC,uBAAuB,EAAE;oBAClF,CAAC,oBAAY,CAAC,EAAE,IAAI;oBACpB,aAAa,EAAb,8BAAa;iBACb,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,MAAM,QAAQ,CAAC;QAChB,CAAC;IACF,CAAC;IAEO,sBAAsB,CAC7B,iBAA4C;QAE5C,8FAA8F;QAC9F,sFAAsF;QACtF,iGAAiG;QACjG,IAAI,IAAI,CAAC,UAAU,IAAI,iBAAiB,IAAI,IAAI,CAAC,UAAU,KAAK,iBAAiB,EAAE,CAAC;YACnF,6EAA6E;YAC7E,yEAAyE;YACzE,OAAO,IAAI,4BAAiB,CAAC,gBAAgB,EAAE,yBAAc,CAAC,wBAAwB,EAAE;gBACvF,aAAa,EAAb,8BAAa;gBACb,WAAW,EAAE,iBAAiB;gBAC9B,WAAW,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAEO,kBAAkB,CAAC,KAAa;QACvC,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IAC3C,CAAC;CACD;AAhZD,oCAgZC;AAED,MAAa,0BAA2B,SAAQ,YAAY;IAG3D,YACoB,KAAsB,EACtB,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;QAE/C,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;QALjC,UAAK,GAAL,KAAK,CAAiB;QACtB,cAAS,GAAT,SAAS,CAAY;QACrB,WAAM,GAAN,MAAM,CAAqB;QAC3B,uBAAkB,GAAlB,kBAAkB,CAAU;QAN/B,wBAAmB,GAAG,IAAI,mBAAQ,EAAQ,CAAC;QAS3D,2DAA2D;QAC3D,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAClD,CAAC;IAES,yBAAyB,CAClC,iBAAqC,EACrC,SAAoB,EACpB,YAAqB,KAAK;QAE1B,KAAK,CAAC,yBAAyB,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAEzE,8GAA8G;QAC9G,0GAA0G;QAC1G,oBAAoB;QACpB,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,+BAA+B;IAC/B,8DAA8D;IACvD,KAAK,CAAC,GAAG,CAAC,KAAa;QAC7B,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE9B,uDAAuD;QACvD,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAW,EAAE,CAAC;YAChC,MAAM,GAAG,MAAM;iBACb,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBACf,iGAAiG;gBACjG,8FAA8F;gBAC9F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACzB,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;gBACpC,CAAC;gBACD,+DAA+D;gBAC/D,OAAO,KAAK,CAAC;YACd,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBAChB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvC,MAAM,KAAK,CAAC;YACb,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAC/B,GAAW,EACX,YAA8C,EAC9C,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,sGAAsG;QACtG,uGAAuG;QACvG,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC;QAEvD,IAAI,CAAC;YACJ,OAAO,MAAM,KAAK,CAAC,mBAAmB,CACrC,GAAG,EACH,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;YACF,8DAA8D;QAC/D,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACrB,+FAA+F;YAC/F,8EAA8E;YAC9E,8EAA8E;YAC9E,IAAI,SAAS,KAAK,aAAa,EAAE,CAAC;gBACjC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACxC,CAAC;YACD,IACC,SAAS,KAAK,aAAa;gBAC3B,sEAAsE;gBACtE,KAAK,CAAC,UAAU,GAAG,GAAG;gBACtB,sEAAsE;gBACtE,KAAK,CAAC,UAAU,GAAG,GAAG;gBACtB,SAAS,EACR,CAAC;gBACF,MAAM,KAAK,CAAC;YACb,CAAC;QACF,CAAC;QAED,gDAAgD;QAChD,yEAAyE;QACzE,wFAAwF;QAExF,gGAAgG;QAChG,wEAAwE;QACxE,+EAA+E;QAC/E,wGAAwG;QACxG,0BAA0B;QAC1B,MAAM,2BAAgB,CAAC,cAAc,CACpC,IAAI,CAAC,MAAM,EACX,EAAE,SAAS,EAAE,qBAAqB,EAAE,EACpC,KAAK,EAAE,KAAK,EAAE,EAAE;YACf,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,0BAA0B;YACjD,IAAI,KAAoC,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;gBAChD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBACvB,OAAO,CAAC,UAAU,CAAC,CAAC;gBACrB,CAAC,EAAE,KAAK,CAAC,CAAC;YACX,CAAC,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;gBAC9B,QAAQ;gBACR,kFAAkF;gBAClF,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;aACnE,CAAC,CAAC;YACH,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;gBACxB,KAAK,CAAC,MAAM,EAAE,CAAC;YAChB,CAAC;QACF,CAAC,EACD,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAC7C,CAAC;QACF,OAAO,KAAK,CAAC,mBAAmB,CAAI,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC;CACD;AA5HD,gEA4HC;AAUD,SAAgB,yBAAyB,CACxC,iBAAkC,EAClC,kBAAuC,EACvC,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;IAE5B,MAAM,YAAY,GAAG,IAAI,0BAA0B,CAClD,iBAAiB,EACjB,SAAS,EACT,MAAM,EACN,kBAAkB,CAClB,CAAC;IACF,OAAO;QACN,KAAK,EAAE;YACN,GAAG,kBAAkB;YACrB,cAAc,EAAE,YAAY;SAC5B;QACD,YAAY;KACZ,CAAC;AACH,CAAC;AApBD,8DAoBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, Deferred } from \"@fluidframework/core-utils/internal\";\nimport {\n\tLocationRedirectionError,\n\tNonRetryableError,\n\tRateLimiter,\n\tThrottlingError,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tICacheEntry,\n\tIEntry,\n\tIFileEntry,\n\tIOdspError,\n\tIOdspErrorAugmentations,\n\tIOdspResolvedUrl,\n\tIPersistedCache,\n\tOdspErrorTypes,\n\tmaximumCacheDurationMs,\n\tsnapshotKey,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tPerformanceEvent,\n\tisFluidError,\n\tloggerToMonitoringContext,\n\tnormalizeError,\n\twrapError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts.js\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic.js\";\nimport { INonPersistentCache, IOdspCache, IPersistedFileCache } from \"./odspCache.js\";\nimport { patchOdspResolvedUrl } from \"./odspLocationRedirection.js\";\nimport {\n\tIOdspResponse,\n\tfetchAndParseAsJSONHelper,\n\tfetchArray,\n\tfetchHelper,\n\tgetOdspResolvedUrl,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\n\n/**\n * @alpha\n */\nexport type FetchType =\n\t| \"blob\"\n\t| \"createBlob\"\n\t| \"createFile\"\n\t| \"joinSession\"\n\t| \"ops\"\n\t| \"test\"\n\t| \"snapshotTree\"\n\t| \"treesLatest\"\n\t| \"uploadSummary\"\n\t| \"push\"\n\t| \"versions\";\n\n/**\n * @alpha\n */\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n/**\n * In ODSP, the concept of \"epoch\" refers to binary updates to files. For example, this might include using\n * version restore, or if the user downloads a Fluid file and then uploads it again. These result in the epoch\n * value being incremented.\n *\n * The implications of these binary updates is that the Fluid state is disrupted: the sequence number might\n * go backwards, the data might be inconsistent with the latest state of collaboration, etc. As a result, it's\n * not safe to continue collaboration across an epoch change. We need to detect these epoch changes and\n * error out from the collaboration.\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 * @alpha\n */\nexport class EpochTracker implements IPersistedFileCache {\n\tprivate _fluidEpoch: string | undefined;\n\n\tprivate readonly snapshotCacheExpiryTimeoutMs: number;\n\tpublic readonly rateLimiter: RateLimiter;\n\tprivate readonly driverId = uuid();\n\t// This tracks the request number made by the driver instance.\n\tprivate networkCallNumber = 1;\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\t// Limits the max number of concurrent requests to 24.\n\t\tthis.rateLimiter = new RateLimiter(24);\n\n\t\t// Matches the TestOverride logic for the policy defined in odspDocumentStorageServiceBase.ts\n\t\tthis.snapshotCacheExpiryTimeoutMs = loggerToMonitoringContext(logger).config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache\",\n\t\t)\n\t\t\t? 0\n\t\t\t: maximumCacheDurationMs;\n\t}\n\n\t// public for UT purposes only!\n\tpublic setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal): void {\n\t\tassert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n\t\tthis._fluidEpoch = epoch;\n\n\t\tthis.logger.sendTelemetryEvent({\n\t\t\teventName: \"EpochLearnedFirstTime\",\n\t\t\tepoch,\n\t\t\tfetchType,\n\t\t\tfromCache,\n\t\t});\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\ttry {\n\t\t\t// Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst value: IVersionedValueWithEpoch = await this.cache.get(\n\t\t\t\tthis.fileEntryFromEntry(entry),\n\t\t\t);\n\t\t\t// Version mismatch between what the runtime expects and what it recieved.\n\t\t\t// The cached value should not be used\n\t\t\tif (value === undefined || value.version !== persistedCacheValueVersion) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tassert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n\t\t\tif (this._fluidEpoch === undefined) {\n\t\t\t\tthis.setEpoch(value.fluidEpoch, true, \"cache\");\n\t\t\t\t// Epoch mismatch, the cached value is considerably different from what the current state of\n\t\t\t\t// the runtime and should not be used\n\t\t\t} else if (this._fluidEpoch !== value.fluidEpoch) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately\n\t\t\t// expire all old caches that do not have cacheEntryTime\n\t\t\tif (entry.type === snapshotKey) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\t\tconst cacheTime = value.value?.cacheEntryTime;\n\t\t\t\tconst currentTime = Date.now();\n\t\t\t\tif (\n\t\t\t\t\tcacheTime === undefined ||\n\t\t\t\t\tcurrentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs\n\t\t\t\t) {\n\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"odspVersionsCacheExpired\",\n\t\t\t\t\t\tduration: currentTime - cacheTime,\n\t\t\t\t\t\tmaxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,\n\t\t\t\t\t});\n\t\t\t\t\tawait this.removeEntries();\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\treturn value.value;\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t// TODO: take a stronger type or `unknown`\n\t// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any\n\tpublic async put(entry: IEntry, value: any): Promise<void> {\n\t\tassert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n\t\t// For snapshots, the value should have the cacheEntryTime.\n\t\t// This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.\n\t\tif (entry.type === snapshotKey) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\tvalue.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n\t\t}\n\t\tconst data: IVersionedValueWithEpoch = {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tvalue,\n\t\t\tversion: persistedCacheValueVersion,\n\t\t\tfluidEpoch: this._fluidEpoch,\n\t\t};\n\t\treturn this.cache.put(this.fileEntryFromEntry(entry), data).catch((error) => {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n\t\t\tthrow error;\n\t\t});\n\t}\n\n\tpublic async removeEntries(): Promise<void> {\n\t\ttry {\n\t\t\treturn await this.cache.removeEntries(this.fileEntry);\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n\t\t}\n\t}\n\n\tpublic get fluidEpoch(): string | undefined {\n\t\treturn this._fluidEpoch;\n\t}\n\n\tpublic async validateEpoch(epoch: string | undefined, fetchType: FetchType): Promise<void> {\n\t\tassert(epoch !== undefined, 0x584 /* response should contain epoch */);\n\t\ttry {\n\t\t\tthis.validateEpochFromResponse(epoch, fetchType);\n\t\t} catch (error) {\n\t\t\tawait this.checkForEpochError(error, epoch, fetchType);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\treturn this.fetchCore<T>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchAndParseAsJSONHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetch(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<Response>> {\n\t\treturn this.fetchCore<Response>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate async fetchCore<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetcher: (url: string, fetchOptions: RequestInit) => Promise<IOdspResponse<T>>,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\tconst clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n\t\t// Add epoch in fetch request.\n\t\tthis.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n\t\tlet epochFromResponse: string | undefined;\n\t\treturn this.rateLimiter\n\t\t\t.schedule(async () => fetcher(url, fetchOptions))\n\t\t\t.then((response) => {\n\t\t\t\tepochFromResponse = response.headers.get(\"x-fluid-epoch\");\n\t\t\t\tthis.validateEpochFromResponse(epochFromResponse, fetchType);\n\t\t\t\tresponse.propsToLog.XRequestStatsHeader = clientCorrelationId;\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.catch(async (error) => {\n\t\t\t\t// Get the server epoch from error in case we don't have it as if undefined we won't be able\n\t\t\t\t// to mark it as epoch error.\n\t\t\t\tif (epochFromResponse === undefined) {\n\t\t\t\t\tepochFromResponse = (error as IOdspError).serverEpoch;\n\t\t\t\t}\n\t\t\t\tawait this.checkForEpochError(error, epochFromResponse, fetchType);\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\t// If the error is about location redirection, then we need to generate new resolved url with correct\n\t\t\t\t// location info.\n\t\t\t\tif (\n\t\t\t\t\tisFluidError(error) &&\n\t\t\t\t\terror.errorType === OdspErrorTypes.fileNotFoundOrAccessDeniedError\n\t\t\t\t) {\n\t\t\t\t\tconst redirectLocation = (error as IOdspErrorAugmentations).redirectLocation;\n\t\t\t\t\tif (redirectLocation !== undefined) {\n\t\t\t\t\t\tconst redirectUrl: IOdspResolvedUrl = patchOdspResolvedUrl(\n\t\t\t\t\t\t\tthis.fileEntry.resolvedUrl,\n\t\t\t\t\t\t\tredirectLocation,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst locationRedirectionError = new LocationRedirectionError(\n\t\t\t\t\t\t\terror.message,\n\t\t\t\t\t\t\tredirectUrl,\n\t\t\t\t\t\t\t{ driverVersion, redirectLocation },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlocationRedirectionError.addTelemetryProperties(error.getTelemetryProperties());\n\t\t\t\t\t\tthrow locationRedirectionError;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconst fluidError = normalizeError(error, {\n\t\t\t\t\tprops: { XRequestStatsHeader: clientCorrelationId },\n\t\t\t\t});\n\t\t\t\tthrow fluidError;\n\t\t\t});\n\t}\n\n\t/**\n\t * Api to fetch the response as it is for given request.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchArray(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<ArrayBuffer>> {\n\t\treturn this.fetchCore<ArrayBuffer>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchArray,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate addEpochInRequest(\n\t\tfetchOptions: RequestInit,\n\t\taddInBody: boolean,\n\t\tclientCorrelationId: string,\n\t): void {\n\t\tconst isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n\t\tif (addInBody) {\n\t\t\tconst headers: { [key: string]: string } = {};\n\t\t\theaders[\"X-RequestStats\"] = clientCorrelationId;\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\theaders[\"x-fluid-epoch\"] = this.fluidEpoch;\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\theaders[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n\t\t\t}\n\t\t\tthis.addParamInBody(fetchOptions, headers);\n\t\t} else {\n\t\t\tconst addHeader = (key: string, val: string): void => {\n\t\t\t\tfetchOptions.headers = {\n\t\t\t\t\t...fetchOptions.headers,\n\t\t\t\t};\n\t\t\t\tassert(\n\t\t\t\t\tfetchOptions.headers !== undefined,\n\t\t\t\t\t0x282 /* \"Headers should be present now\" */,\n\t\t\t\t);\n\t\t\t\tfetchOptions.headers[key] = val;\n\t\t\t};\n\t\t\taddHeader(\"X-RequestStats\", clientCorrelationId);\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\taddHeader(\"x-fluid-epoch\", this.fluidEpoch);\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\taddHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addParamInBody(fetchOptions: RequestInit, headers: { [key: string]: string }): void {\n\t\t// We use multi part form request for post body where we want to use this.\n\t\t// So extract the form boundary to mark the end of form.\n\t\tconst body = fetchOptions.body;\n\t\tassert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n\t\tconst splitBody = body.split(\"\\r\\n\");\n\t\tconst firstLine = splitBody.shift();\n\t\tassert(firstLine?.startsWith(\"--\") === true, 0x21e /* \"improper boundary format\" */);\n\t\tconst formParams = [firstLine];\n\t\tfor (const [key, value] of Object.entries(headers)) {\n\t\t\tformParams.push(`${key}: ${value}`);\n\t\t}\n\t\tfor (const value of splitBody) {\n\t\t\tformParams.push(value);\n\t\t}\n\t\tfetchOptions.body = formParams.join(\"\\r\\n\");\n\t}\n\n\tprivate formatClientCorrelationId(fetchReason?: string): string {\n\t\tconst items: string[] = [\n\t\t\t`driverId=${this.driverId}`,\n\t\t\t`RequestNumber=${this.networkCallNumber++}`,\n\t\t\t`driverVersion=${driverVersion}`,\n\t\t\t`isSummarizer=${this.clientIsSummarizer}`,\n\t\t];\n\t\tif (fetchReason !== undefined) {\n\t\t\titems.push(`fetchReason=${fetchReason}`);\n\t\t}\n\t\treturn items.join(\", \");\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tconst error = this.checkForEpochErrorCore(epochFromResponse);\n\t\tif (error !== undefined) {\n\t\t\tthrow error;\n\t\t}\n\t\tif (epochFromResponse !== undefined && this._fluidEpoch === undefined) {\n\t\t\tthis.setEpoch(epochFromResponse, fromCache, fetchType);\n\t\t}\n\t}\n\n\tprivate async checkForEpochError(\n\t\terror: unknown,\n\t\tepochFromResponse: string | null | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): Promise<void> {\n\t\tif (isFluidError(error) && error.errorType === OdspErrorTypes.fileOverwrittenInStorage) {\n\t\t\tconst epochError = this.checkForEpochErrorCore(epochFromResponse);\n\t\t\tif (epochError !== undefined) {\n\t\t\t\tepochError.addTelemetryProperties({\n\t\t\t\t\tfromCache,\n\t\t\t\t\tfetchType,\n\t\t\t\t});\n\t\t\t\tthis.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n\t\t\t\t// If the epoch mismatches, then clear all entries for such file entry from cache.\n\t\t\t\tawait this.removeEntries();\n\t\t\t\tthrow epochError;\n\t\t\t}\n\t\t\t// If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n\t\t\t// then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n\t\t\t// time is 1s.\n\t\t\tconst newError = wrapError(error, (message: string) => {\n\t\t\t\treturn new ThrottlingError(`Coherency 409: ${message}`, 1 /* retryAfterSeconds */, {\n\t\t\t\t\t[Odsp409Error]: true,\n\t\t\t\t\tdriverVersion,\n\t\t\t\t});\n\t\t\t});\n\t\t\tthrow newError;\n\t\t}\n\t}\n\n\tprivate checkForEpochErrorCore(\n\t\tepochFromResponse: string | null | undefined,\n\t): NonRetryableError<\"fileOverwrittenInStorage\"> | undefined {\n\t\t// If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n\t\t// initializes this value. Sometimes response does not contain epoch as it is still in\n\t\t// implementation phase at server side. In that case also, don't compare it with our epoch value.\n\t\tif (this.fluidEpoch && epochFromResponse && this.fluidEpoch !== epochFromResponse) {\n\t\t\t// This is similar in nature to how fluidEpochMismatchError (409) is handled.\n\t\t\t// Difference - client detected mismatch, instead of server detecting it.\n\t\t\treturn new NonRetryableError(\"Epoch mismatch\", OdspErrorTypes.fileOverwrittenInStorage, {\n\t\t\t\tdriverVersion,\n\t\t\t\tserverEpoch: epochFromResponse,\n\t\t\t\tclientEpoch: this.fluidEpoch,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate fileEntryFromEntry(entry: IEntry): ICacheEntry {\n\t\treturn { ...entry, file: this.fileEntry };\n\t}\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n\tprivate readonly treesLatestDeferral = new Deferred<void>();\n\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\tsuper(cache, fileEntry, logger, clientIsSummarizer);\n\t\t// Handles the rejected promise within treesLatestDeferral.\n\t\tthis.treesLatestDeferral.promise.catch(() => {});\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchType,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tsuper.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n\t\t// Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n\t\t// That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n\t\t// exploring a file.\n\t\tthis.treesLatestDeferral.resolve();\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\tlet result = super.get(entry);\n\n\t\t// equivalence of what happens in fetchAndParseAsJSON()\n\t\tif (entry.type === snapshotKey) {\n\t\t\tresult = result\n\t\t\t\t.then((value) => {\n\t\t\t\t\t// If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n\t\t\t\t\t// Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n\t\t\t\t\tif (value !== undefined) {\n\t\t\t\t\t\tthis.treesLatestDeferral.resolve();\n\t\t\t\t\t}\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\t\t\treturn value;\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\t// Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n\t\t// joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n\t\tconst completed = this.treesLatestDeferral.isCompleted;\n\n\t\ttry {\n\t\t\treturn await super.fetchAndParseAsJSON<T>(\n\t\t\t\turl,\n\t\t\t\tfetchOptions,\n\t\t\t\tfetchType,\n\t\t\t\taddInBody,\n\t\t\t\tfetchReason,\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t} catch (error: any) {\n\t\t\t// Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n\t\t\t// Similar, if getVersions failed, we should not do any further storage calls.\n\t\t\t// So treesLatest is the only call that can have parallel joinSession request.\n\t\t\tif (fetchType === \"treesLatest\") {\n\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tfetchType !== \"joinSession\" ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode < 401 ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode > 404 ||\n\t\t\t\tcompleted\n\t\t\t) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// It is joinSession failing with 401..404 error\n\t\t// Repeat after waiting for treeLatest succeeding (or fail if it failed).\n\t\t// No special handling after first call - if file has been deleted, then it's game over.\n\n\t\t// Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n\t\t// If we waited too long, we will log error event and proceed with call.\n\t\t// It may result in failure for user, but refreshing document would address it.\n\t\t// Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n\t\t// to unblock the process.\n\t\tawait PerformanceEvent.timedExecAsync(\n\t\t\tthis.logger,\n\t\t\t{ eventName: \"JoinSessionSyncWait\" },\n\t\t\tasync (event) => {\n\t\t\t\tconst timeoutRes = 51; // anything will work here\n\t\t\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t\t\tconst timeoutP = new Promise<number>((resolve) => {\n\t\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\t\tresolve(timeoutRes);\n\t\t\t\t\t}, 15000);\n\t\t\t\t});\n\t\t\t\tconst res = await Promise.race([\n\t\t\t\t\ttimeoutP,\n\t\t\t\t\t// cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n\t\t\t\t\tthis.treesLatestDeferral.promise.finally(() => clearTimeout(timer)),\n\t\t\t\t]);\n\t\t\t\tif (res === timeoutRes) {\n\t\t\t\t\tevent.cancel();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ start: true, end: true, cancel: \"generic\" },\n\t\t);\n\t\treturn super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n\t}\n}\n\n/**\n * @alpha\n */\nexport interface ICacheAndTracker {\n\tcache: IOdspCache;\n\tepochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n\tpersistedCacheArg: IPersistedCache,\n\tnonpersistentCache: INonPersistentCache,\n\tfileEntry: IFileEntry,\n\tlogger: ITelemetryLoggerExt,\n\tclientIsSummarizer?: boolean,\n): ICacheAndTracker {\n\tconst epochTracker = new EpochTrackerWithRedemption(\n\t\tpersistedCacheArg,\n\t\tfileEntry,\n\t\tlogger,\n\t\tclientIsSummarizer,\n\t);\n\treturn {\n\t\tcache: {\n\t\t\t...nonpersistentCache,\n\t\t\tpersistedCache: epochTracker,\n\t\t},\n\t\tepochTracker,\n\t};\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 { assert, Deferred } from \"@fluidframework/core-utils/internal\";\nimport {\n\tLocationRedirectionError,\n\tNonRetryableError,\n\tRateLimiter,\n\tThrottlingError,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tICacheEntry,\n\tIEntry,\n\tIFileEntry,\n\tIOdspError,\n\tIOdspErrorAugmentations,\n\tIOdspResolvedUrl,\n\tIPersistedCache,\n\tOdspErrorTypes,\n\tmaximumCacheDurationMs,\n\tsnapshotKey,\n\tsnapshotWithLoadingGroupIdKey,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tPerformanceEvent,\n\tisFluidError,\n\tloggerToMonitoringContext,\n\tnormalizeError,\n\twrapError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts.js\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic.js\";\nimport { INonPersistentCache, IOdspCache, IPersistedFileCache } from \"./odspCache.js\";\nimport { patchOdspResolvedUrl } from \"./odspLocationRedirection.js\";\nimport {\n\tIOdspResponse,\n\tfetchAndParseAsJSONHelper,\n\tfetchArray,\n\tfetchHelper,\n\tgetOdspResolvedUrl,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\n\n/**\n * @alpha\n */\nexport type FetchType =\n\t| \"blob\"\n\t| \"createBlob\"\n\t| \"createFile\"\n\t| \"joinSession\"\n\t| \"ops\"\n\t| \"test\"\n\t| \"snapshotTree\"\n\t| \"treesLatest\"\n\t| \"uploadSummary\"\n\t| \"push\"\n\t| \"versions\";\n\n/**\n * @alpha\n */\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n/**\n * In ODSP, the concept of \"epoch\" refers to binary updates to files. For example, this might include using\n * version restore, or if the user downloads a Fluid file and then uploads it again. These result in the epoch\n * value being incremented.\n *\n * The implications of these binary updates is that the Fluid state is disrupted: the sequence number might\n * go backwards, the data might be inconsistent with the latest state of collaboration, etc. As a result, it's\n * not safe to continue collaboration across an epoch change. We need to detect these epoch changes and\n * error out from the collaboration.\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 * @alpha\n */\nexport class EpochTracker implements IPersistedFileCache {\n\tprivate _fluidEpoch: string | undefined;\n\n\tprivate readonly snapshotCacheExpiryTimeoutMs: number;\n\tpublic readonly rateLimiter: RateLimiter;\n\tprivate readonly driverId = uuid();\n\t// This tracks the request number made by the driver instance.\n\tprivate networkCallNumber = 1;\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\t// Limits the max number of concurrent requests to 24.\n\t\tthis.rateLimiter = new RateLimiter(24);\n\n\t\t// Matches the TestOverride logic for the policy defined in odspDocumentStorageServiceBase.ts\n\t\tthis.snapshotCacheExpiryTimeoutMs = loggerToMonitoringContext(logger).config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache\",\n\t\t)\n\t\t\t? 0\n\t\t\t: maximumCacheDurationMs;\n\t}\n\n\t// public for UT purposes only!\n\tpublic setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal): void {\n\t\tassert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n\t\tthis._fluidEpoch = epoch;\n\n\t\tthis.logger.sendTelemetryEvent({\n\t\t\teventName: \"EpochLearnedFirstTime\",\n\t\t\tepoch,\n\t\t\tfetchType,\n\t\t\tfromCache,\n\t\t});\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\ttry {\n\t\t\t// Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst value: IVersionedValueWithEpoch = await this.cache.get(\n\t\t\t\tthis.fileEntryFromEntry(entry),\n\t\t\t);\n\t\t\t// Version mismatch between what the runtime expects and what it recieved.\n\t\t\t// The cached value should not be used\n\t\t\tif (value === undefined || value.version !== persistedCacheValueVersion) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tassert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n\t\t\tif (this._fluidEpoch === undefined) {\n\t\t\t\tthis.setEpoch(value.fluidEpoch, true, \"cache\");\n\t\t\t\t// Epoch mismatch, the cached value is considerably different from what the current state of\n\t\t\t\t// the runtime and should not be used\n\t\t\t} else if (this._fluidEpoch !== value.fluidEpoch) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately\n\t\t\t// expire all old caches that do not have cacheEntryTime\n\t\t\tif (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\t\tconst cacheTime = value.value?.cacheEntryTime;\n\t\t\t\tconst currentTime = Date.now();\n\t\t\t\tif (\n\t\t\t\t\tcacheTime === undefined ||\n\t\t\t\t\tcurrentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs\n\t\t\t\t) {\n\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"odspVersionsCacheExpired\",\n\t\t\t\t\t\tduration: currentTime - cacheTime,\n\t\t\t\t\t\tmaxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,\n\t\t\t\t\t});\n\t\t\t\t\tawait this.removeEntries();\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\treturn value.value;\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t// TODO: take a stronger type or `unknown`\n\t// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any\n\tpublic async put(entry: IEntry, value: any): Promise<void> {\n\t\tassert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n\t\t// For snapshots, the value should have the cacheEntryTime.\n\t\t// This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.\n\t\tif (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\tvalue.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n\t\t}\n\t\tconst data: IVersionedValueWithEpoch = {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tvalue,\n\t\t\tversion: persistedCacheValueVersion,\n\t\t\tfluidEpoch: this._fluidEpoch,\n\t\t};\n\t\treturn this.cache.put(this.fileEntryFromEntry(entry), data).catch((error) => {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n\t\t\tthrow error;\n\t\t});\n\t}\n\n\tpublic async removeEntries(): Promise<void> {\n\t\ttry {\n\t\t\treturn await this.cache.removeEntries(this.fileEntry);\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n\t\t}\n\t}\n\n\tpublic get fluidEpoch(): string | undefined {\n\t\treturn this._fluidEpoch;\n\t}\n\n\tpublic async validateEpoch(epoch: string | undefined, fetchType: FetchType): Promise<void> {\n\t\tassert(epoch !== undefined, 0x584 /* response should contain epoch */);\n\t\ttry {\n\t\t\tthis.validateEpochFromResponse(epoch, fetchType);\n\t\t} catch (error) {\n\t\t\tawait this.checkForEpochError(error, epoch, fetchType);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\treturn this.fetchCore<T>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchAndParseAsJSONHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetch(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<Response>> {\n\t\treturn this.fetchCore<Response>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate async fetchCore<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetcher: (url: string, fetchOptions: RequestInit) => Promise<IOdspResponse<T>>,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\tconst clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n\t\t// Add epoch in fetch request.\n\t\tthis.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n\t\tlet epochFromResponse: string | undefined;\n\t\treturn this.rateLimiter\n\t\t\t.schedule(async () => fetcher(url, fetchOptions))\n\t\t\t.then((response) => {\n\t\t\t\tepochFromResponse = response.headers.get(\"x-fluid-epoch\");\n\t\t\t\tthis.validateEpochFromResponse(epochFromResponse, fetchType);\n\t\t\t\tresponse.propsToLog.XRequestStatsHeader = clientCorrelationId;\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.catch(async (error) => {\n\t\t\t\t// Get the server epoch from error in case we don't have it as if undefined we won't be able\n\t\t\t\t// to mark it as epoch error.\n\t\t\t\tif (epochFromResponse === undefined) {\n\t\t\t\t\tepochFromResponse = (error as IOdspError).serverEpoch;\n\t\t\t\t}\n\t\t\t\tawait this.checkForEpochError(error, epochFromResponse, fetchType);\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\t// If the error is about location redirection, then we need to generate new resolved url with correct\n\t\t\t\t// location info.\n\t\t\t\tif (\n\t\t\t\t\tisFluidError(error) &&\n\t\t\t\t\terror.errorType === OdspErrorTypes.fileNotFoundOrAccessDeniedError\n\t\t\t\t) {\n\t\t\t\t\tconst redirectLocation = (error as IOdspErrorAugmentations).redirectLocation;\n\t\t\t\t\tif (redirectLocation !== undefined) {\n\t\t\t\t\t\tconst redirectUrl: IOdspResolvedUrl = patchOdspResolvedUrl(\n\t\t\t\t\t\t\tthis.fileEntry.resolvedUrl,\n\t\t\t\t\t\t\tredirectLocation,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst locationRedirectionError = new LocationRedirectionError(\n\t\t\t\t\t\t\terror.message,\n\t\t\t\t\t\t\tredirectUrl,\n\t\t\t\t\t\t\t{ driverVersion, redirectLocation },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlocationRedirectionError.addTelemetryProperties(error.getTelemetryProperties());\n\t\t\t\t\t\tthrow locationRedirectionError;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconst fluidError = normalizeError(error, {\n\t\t\t\t\tprops: { XRequestStatsHeader: clientCorrelationId },\n\t\t\t\t});\n\t\t\t\tthrow fluidError;\n\t\t\t});\n\t}\n\n\t/**\n\t * Api to fetch the response as it is for given request.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchArray(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<ArrayBuffer>> {\n\t\treturn this.fetchCore<ArrayBuffer>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchArray,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate addEpochInRequest(\n\t\tfetchOptions: RequestInit,\n\t\taddInBody: boolean,\n\t\tclientCorrelationId: string,\n\t): void {\n\t\tconst isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n\t\tif (addInBody) {\n\t\t\tconst headers: { [key: string]: string } = {};\n\t\t\theaders[\"X-RequestStats\"] = clientCorrelationId;\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\theaders[\"x-fluid-epoch\"] = this.fluidEpoch;\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\theaders[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n\t\t\t}\n\t\t\tthis.addParamInBody(fetchOptions, headers);\n\t\t} else {\n\t\t\tconst addHeader = (key: string, val: string): void => {\n\t\t\t\tfetchOptions.headers = {\n\t\t\t\t\t...fetchOptions.headers,\n\t\t\t\t};\n\t\t\t\tassert(\n\t\t\t\t\tfetchOptions.headers !== undefined,\n\t\t\t\t\t0x282 /* \"Headers should be present now\" */,\n\t\t\t\t);\n\t\t\t\tfetchOptions.headers[key] = val;\n\t\t\t};\n\t\t\taddHeader(\"X-RequestStats\", clientCorrelationId);\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\taddHeader(\"x-fluid-epoch\", this.fluidEpoch);\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\taddHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addParamInBody(fetchOptions: RequestInit, headers: { [key: string]: string }): void {\n\t\t// We use multi part form request for post body where we want to use this.\n\t\t// So extract the form boundary to mark the end of form.\n\t\tconst body = fetchOptions.body;\n\t\tassert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n\t\tconst splitBody = body.split(\"\\r\\n\");\n\t\tconst firstLine = splitBody.shift();\n\t\tassert(firstLine?.startsWith(\"--\") === true, 0x21e /* \"improper boundary format\" */);\n\t\tconst formParams = [firstLine];\n\t\tfor (const [key, value] of Object.entries(headers)) {\n\t\t\tformParams.push(`${key}: ${value}`);\n\t\t}\n\t\tfor (const value of splitBody) {\n\t\t\tformParams.push(value);\n\t\t}\n\t\tfetchOptions.body = formParams.join(\"\\r\\n\");\n\t}\n\n\tprivate formatClientCorrelationId(fetchReason?: string): string {\n\t\tconst items: string[] = [\n\t\t\t`driverId=${this.driverId}`,\n\t\t\t`RequestNumber=${this.networkCallNumber++}`,\n\t\t\t`driverVersion=${driverVersion}`,\n\t\t\t`isSummarizer=${this.clientIsSummarizer}`,\n\t\t];\n\t\tif (fetchReason !== undefined) {\n\t\t\titems.push(`fetchReason=${fetchReason}`);\n\t\t}\n\t\treturn items.join(\", \");\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tconst error = this.checkForEpochErrorCore(epochFromResponse);\n\t\tif (error !== undefined) {\n\t\t\tthrow error;\n\t\t}\n\t\tif (epochFromResponse !== undefined && this._fluidEpoch === undefined) {\n\t\t\tthis.setEpoch(epochFromResponse, fromCache, fetchType);\n\t\t}\n\t}\n\n\tprivate async checkForEpochError(\n\t\terror: unknown,\n\t\tepochFromResponse: string | null | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): Promise<void> {\n\t\tif (isFluidError(error) && error.errorType === OdspErrorTypes.fileOverwrittenInStorage) {\n\t\t\tconst epochError = this.checkForEpochErrorCore(epochFromResponse);\n\t\t\tif (epochError !== undefined) {\n\t\t\t\tepochError.addTelemetryProperties({\n\t\t\t\t\tfromCache,\n\t\t\t\t\tfetchType,\n\t\t\t\t});\n\t\t\t\tthis.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n\t\t\t\t// If the epoch mismatches, then clear all entries for such file entry from cache.\n\t\t\t\tawait this.removeEntries();\n\t\t\t\tthrow epochError;\n\t\t\t}\n\t\t\t// If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n\t\t\t// then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n\t\t\t// time is 1s.\n\t\t\tconst newError = wrapError(error, (message: string) => {\n\t\t\t\treturn new ThrottlingError(`Coherency 409: ${message}`, 1 /* retryAfterSeconds */, {\n\t\t\t\t\t[Odsp409Error]: true,\n\t\t\t\t\tdriverVersion,\n\t\t\t\t});\n\t\t\t});\n\t\t\tthrow newError;\n\t\t}\n\t}\n\n\tprivate checkForEpochErrorCore(\n\t\tepochFromResponse: string | null | undefined,\n\t): NonRetryableError<\"fileOverwrittenInStorage\"> | undefined {\n\t\t// If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n\t\t// initializes this value. Sometimes response does not contain epoch as it is still in\n\t\t// implementation phase at server side. In that case also, don't compare it with our epoch value.\n\t\tif (this.fluidEpoch && epochFromResponse && this.fluidEpoch !== epochFromResponse) {\n\t\t\t// This is similar in nature to how fluidEpochMismatchError (409) is handled.\n\t\t\t// Difference - client detected mismatch, instead of server detecting it.\n\t\t\treturn new NonRetryableError(\"Epoch mismatch\", OdspErrorTypes.fileOverwrittenInStorage, {\n\t\t\t\tdriverVersion,\n\t\t\t\tserverEpoch: epochFromResponse,\n\t\t\t\tclientEpoch: this.fluidEpoch,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate fileEntryFromEntry(entry: IEntry): ICacheEntry {\n\t\treturn { ...entry, file: this.fileEntry };\n\t}\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n\tprivate readonly treesLatestDeferral = new Deferred<void>();\n\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\tsuper(cache, fileEntry, logger, clientIsSummarizer);\n\t\t// Handles the rejected promise within treesLatestDeferral.\n\t\tthis.treesLatestDeferral.promise.catch(() => {});\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchType,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tsuper.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n\t\t// Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n\t\t// That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n\t\t// exploring a file.\n\t\tthis.treesLatestDeferral.resolve();\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\tlet result = super.get(entry);\n\n\t\t// equivalence of what happens in fetchAndParseAsJSON()\n\t\tif (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {\n\t\t\tresult = result\n\t\t\t\t.then((value) => {\n\t\t\t\t\t// If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n\t\t\t\t\t// Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n\t\t\t\t\tif (value !== undefined) {\n\t\t\t\t\t\tthis.treesLatestDeferral.resolve();\n\t\t\t\t\t}\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\t\t\treturn value;\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\t// Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n\t\t// joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n\t\tconst completed = this.treesLatestDeferral.isCompleted;\n\n\t\ttry {\n\t\t\treturn await super.fetchAndParseAsJSON<T>(\n\t\t\t\turl,\n\t\t\t\tfetchOptions,\n\t\t\t\tfetchType,\n\t\t\t\taddInBody,\n\t\t\t\tfetchReason,\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t} catch (error: any) {\n\t\t\t// Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n\t\t\t// Similar, if getVersions failed, we should not do any further storage calls.\n\t\t\t// So treesLatest is the only call that can have parallel joinSession request.\n\t\t\tif (fetchType === \"treesLatest\") {\n\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tfetchType !== \"joinSession\" ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode < 401 ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode > 404 ||\n\t\t\t\tcompleted\n\t\t\t) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// It is joinSession failing with 401..404 error\n\t\t// Repeat after waiting for treeLatest succeeding (or fail if it failed).\n\t\t// No special handling after first call - if file has been deleted, then it's game over.\n\n\t\t// Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n\t\t// If we waited too long, we will log error event and proceed with call.\n\t\t// It may result in failure for user, but refreshing document would address it.\n\t\t// Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n\t\t// to unblock the process.\n\t\tawait PerformanceEvent.timedExecAsync(\n\t\t\tthis.logger,\n\t\t\t{ eventName: \"JoinSessionSyncWait\" },\n\t\t\tasync (event) => {\n\t\t\t\tconst timeoutRes = 51; // anything will work here\n\t\t\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t\t\tconst timeoutP = new Promise<number>((resolve) => {\n\t\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\t\tresolve(timeoutRes);\n\t\t\t\t\t}, 15000);\n\t\t\t\t});\n\t\t\t\tconst res = await Promise.race([\n\t\t\t\t\ttimeoutP,\n\t\t\t\t\t// cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n\t\t\t\t\tthis.treesLatestDeferral.promise.finally(() => clearTimeout(timer)),\n\t\t\t\t]);\n\t\t\t\tif (res === timeoutRes) {\n\t\t\t\t\tevent.cancel();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ start: true, end: true, cancel: \"generic\" },\n\t\t);\n\t\treturn super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n\t}\n}\n\n/**\n * @alpha\n */\nexport interface ICacheAndTracker {\n\tcache: IOdspCache;\n\tepochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n\tpersistedCacheArg: IPersistedCache,\n\tnonpersistentCache: INonPersistentCache,\n\tfileEntry: IFileEntry,\n\tlogger: ITelemetryLoggerExt,\n\tclientIsSummarizer?: boolean,\n): ICacheAndTracker {\n\tconst epochTracker = new EpochTrackerWithRedemption(\n\t\tpersistedCacheArg,\n\t\tfileEntry,\n\t\tlogger,\n\t\tclientIsSummarizer,\n\t);\n\treturn {\n\t\tcache: {\n\t\t\t...nonpersistentCache,\n\t\t\tpersistedCache: epochTracker,\n\t\t},\n\t\tepochTracker,\n\t};\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.0.5";
8
+ export declare const pkgVersion = "2.0.6";
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.0.5";
11
+ exports.pkgVersion = "2.0.6";
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,OAAO,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.0.5\";\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,OAAO,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.0.6\";\n"]}
@@ -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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"}
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { assert, Deferred } from "@fluidframework/core-utils/internal";
6
6
  import { LocationRedirectionError, NonRetryableError, RateLimiter, ThrottlingError, } from "@fluidframework/driver-utils/internal";
7
- import { OdspErrorTypes, maximumCacheDurationMs, snapshotKey, } from "@fluidframework/odsp-driver-definitions/internal";
7
+ import { OdspErrorTypes, maximumCacheDurationMs, snapshotKey, snapshotWithLoadingGroupIdKey, } from "@fluidframework/odsp-driver-definitions/internal";
8
8
  import { PerformanceEvent, isFluidError, loggerToMonitoringContext, normalizeError, wrapError, } from "@fluidframework/telemetry-utils/internal";
9
9
  import { v4 as uuid } from "uuid";
10
10
  import { persistedCacheValueVersion } from "./contracts.js";
@@ -79,7 +79,7 @@ export class EpochTracker {
79
79
  }
80
80
  // Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately
81
81
  // expire all old caches that do not have cacheEntryTime
82
- if (entry.type === snapshotKey) {
82
+ if (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {
83
83
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
84
84
  const cacheTime = value.value?.cacheEntryTime;
85
85
  const currentTime = Date.now();
@@ -108,7 +108,7 @@ export class EpochTracker {
108
108
  assert(this._fluidEpoch !== undefined, 0x1dd /* "no epoch" */);
109
109
  // For snapshots, the value should have the cacheEntryTime.
110
110
  // This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.
111
- if (entry.type === snapshotKey) {
111
+ if (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {
112
112
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
113
113
  value.cacheEntryTime = value.cacheEntryTime ?? Date.now();
114
114
  }
@@ -355,7 +355,7 @@ export class EpochTrackerWithRedemption extends EpochTracker {
355
355
  async get(entry) {
356
356
  let result = super.get(entry);
357
357
  // equivalence of what happens in fetchAndParseAsJSON()
358
- if (entry.type === snapshotKey) {
358
+ if (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {
359
359
  result = result
360
360
  .then((value) => {
361
361
  // If there is nothing in cache, we need to wait for network call to complete (and do redemption)
@@ -1 +1 @@
1
- {"version":3,"file":"epochTracker.js","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EACN,wBAAwB,EACxB,iBAAiB,EACjB,WAAW,EACX,eAAe,GACf,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAQN,cAAc,EACd,sBAAsB,EACtB,WAAW,GACX,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,gBAAgB,EAChB,YAAY,EACZ,yBAAyB,EACzB,cAAc,EACd,SAAS,GACT,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EAA4B,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAEN,yBAAyB,EACzB,UAAU,EACV,WAAW,EACX,kBAAkB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAuBlE,MAAM,CAAC,MAAM,YAAY,GAAG,cAAc,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,YAAY;IAQxB,YACoB,KAAsB,EACtB,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;QAH5B,UAAK,GAAL,KAAK,CAAiB;QACtB,cAAS,GAAT,SAAS,CAAY;QACrB,WAAM,GAAN,MAAM,CAAqB;QAC3B,uBAAkB,GAAlB,kBAAkB,CAAU;QAP/B,aAAQ,GAAG,IAAI,EAAE,CAAC;QACnC,8DAA8D;QACtD,sBAAiB,GAAG,CAAC,CAAC;QAO7B,sDAAsD;QACtD,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;QAEvC,6FAA6F;QAC7F,IAAI,CAAC,4BAA4B,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,UAAU,CACtF,qDAAqD,CACrD;YACA,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,sBAAsB,CAAC;IAC3B,CAAC;IAED,+BAA+B;IACxB,QAAQ,CAAC,KAAa,EAAE,SAAkB,EAAE,SAA4B;QAC9E,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAEzB,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAC9B,SAAS,EAAE,uBAAuB;YAClC,KAAK;YACL,SAAS;YACT,SAAS;SACT,CAAC,CAAC;IACJ,CAAC;IAED,+BAA+B;IAC/B,8DAA8D;IACvD,KAAK,CAAC,GAAG,CAAC,KAAa;QAC7B,IAAI,CAAC;YACJ,8FAA8F;YAC9F,mEAAmE;YACnE,MAAM,KAAK,GAA6B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAC3D,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAC9B,CAAC;YACF,0EAA0E;YAC1E,sCAAsC;YACtC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,0BAA0B,EAAE,CAAC;gBACzE,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACrF,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC/C,4FAA4F;gBAC5F,qCAAqC;YACtC,CAAC;iBAAM,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC;gBAClD,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,6FAA6F;YAC7F,wDAAwD;YACxD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAChC,+GAA+G;gBAC/G,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC;gBAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC/B,IACC,SAAS,KAAK,SAAS;oBACvB,WAAW,GAAG,SAAS,IAAI,IAAI,CAAC,4BAA4B,EAC3D,CAAC;oBACF,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;wBAC9B,SAAS,EAAE,0BAA0B;wBACrC,QAAQ,EAAE,WAAW,GAAG,SAAS;wBACjC,aAAa,EAAE,IAAI,CAAC,4BAA4B;qBAChD,CAAC,CAAC;oBACH,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC3B,OAAO,SAAS,CAAC;gBAClB,CAAC;YACF,CAAC;YACD,+DAA+D;YAC/D,OAAO,KAAK,CAAC,KAAK,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACtF,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IAED,0CAA0C;IAC1C,iHAAiH;IAC1G,KAAK,CAAC,GAAG,CAAC,KAAa,EAAE,KAAU;QACzC,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC/D,2DAA2D;QAC3D,iFAAiF;QACjF,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAChC,+GAA+G;YAC/G,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3D,CAAC;QACD,MAAM,IAAI,GAA6B;YACtC,mEAAmE;YACnE,KAAK;YACL,OAAO,EAAE,0BAA0B;YACnC,UAAU,EAAE,IAAI,CAAC,WAAW;SAC5B,CAAC;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC3E,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACpF,MAAM,KAAK,CAAC;QACb,CAAC,CAAC,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,aAAa;QACzB,IAAI,CAAC;YACJ,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,EAAE,KAAK,CAAC,CAAC;QACxE,CAAC;IACF,CAAC;IAED,IAAW,UAAU;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,KAAyB,EAAE,SAAoB;QACzE,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvE,IAAI,CAAC;YACJ,IAAI,CAAC,yBAAyB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,mBAAmB,CAC/B,GAAW,EACX,YAAyB,EACzB,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,yBAAyB,EACzB,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,KAAK,CACjB,GAAW,EACX,YAAyB,EACzB,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,WAAW,EACX,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS,CACtB,GAAW,EACX,YAAyB,EACzB,OAA8E,EAC9E,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,MAAM,mBAAmB,GAAG,IAAI,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC;QACxE,8BAA8B;QAC9B,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;QACrE,IAAI,iBAAqC,CAAC;QAC1C,OAAO,IAAI,CAAC,WAAW;aACrB,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;aAChD,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClB,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC1D,IAAI,CAAC,yBAAyB,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;YAC7D,QAAQ,CAAC,UAAU,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;YAC9D,OAAO,QAAQ,CAAC;QACjB,CAAC,CAAC;aACD,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACtB,4FAA4F;YAC5F,6BAA6B;YAC7B,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACrC,iBAAiB,GAAI,KAAoB,CAAC,WAAW,CAAC;YACvD,CAAC;YACD,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC;YACnE,MAAM,KAAK,CAAC;QACb,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,qGAAqG;YACrG,iBAAiB;YACjB,IACC,YAAY,CAAC,KAAK,CAAC;gBACnB,KAAK,CAAC,SAAS,KAAK,cAAc,CAAC,+BAA+B,EACjE,CAAC;gBACF,MAAM,gBAAgB,GAAI,KAAiC,CAAC,gBAAgB,CAAC;gBAC7E,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;oBACpC,MAAM,WAAW,GAAqB,oBAAoB,CACzD,IAAI,CAAC,SAAS,CAAC,WAAW,EAC1B,gBAAgB,CAChB,CAAC;oBACF,MAAM,wBAAwB,GAAG,IAAI,wBAAwB,CAC5D,KAAK,CAAC,OAAO,EACb,WAAW,EACX,EAAE,aAAa,EAAE,gBAAgB,EAAE,CACnC,CAAC;oBACF,wBAAwB,CAAC,sBAAsB,CAAC,KAAK,CAAC,sBAAsB,EAAE,CAAC,CAAC;oBAChF,MAAM,wBAAwB,CAAC;gBAChC,CAAC;YACF,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,EAAE;gBACxC,KAAK,EAAE,EAAE,mBAAmB,EAAE,mBAAmB,EAAE;aACnD,CAAC,CAAC;YACH,MAAM,UAAU,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,UAAU,CACtB,GAAW,EACX,YAA8C,EAC9C,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAEO,iBAAiB,CACxB,YAAyB,EACzB,SAAkB,EAClB,mBAA2B;QAE3B,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,iBAAiB,CAAC;QAC3F,IAAI,SAAS,EAAE,CAAC;YACf,MAAM,OAAO,GAA8B,EAAE,CAAC;YAC9C,OAAO,CAAC,gBAAgB,CAAC,GAAG,mBAAmB,CAAC;YAChD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACnC,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC5C,CAAC;YACD,IAAI,iBAAiB,EAAE,CAAC;gBACvB,OAAO,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YACjF,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACP,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,GAAW,EAAQ,EAAE;gBACpD,YAAY,CAAC,OAAO,GAAG;oBACtB,GAAG,YAAY,CAAC,OAAO;iBACvB,CAAC;gBACF,MAAM,CACL,YAAY,CAAC,OAAO,KAAK,SAAS,EAClC,KAAK,CAAC,qCAAqC,CAC3C,CAAC;gBACF,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YACjC,CAAC,CAAC;YACF,SAAS,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACnC,SAAS,CAAC,eAAe,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7C,CAAC;YACD,IAAI,iBAAiB,EAAE,CAAC;gBACvB,SAAS,CAAC,qBAAqB,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC;YAClF,CAAC;QACF,CAAC;IACF,CAAC;IAEO,cAAc,CAAC,YAAyB,EAAE,OAAkC;QACnF,0EAA0E;QAC1E,wDAAwD;QACxD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;QAC/B,MAAM,CAAC,OAAO,IAAI,KAAK,QAAQ,EAAE,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACnE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACrF,MAAM,UAAU,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACpD,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC/B,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,YAAY,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAEO,yBAAyB,CAAC,WAAoB;QACrD,MAAM,KAAK,GAAa;YACvB,YAAY,IAAI,CAAC,QAAQ,EAAE;YAC3B,iBAAiB,IAAI,CAAC,iBAAiB,EAAE,EAAE;YAC3C,iBAAiB,aAAa,EAAE;YAChC,gBAAgB,IAAI,CAAC,kBAAkB,EAAE;SACzC,CAAC;QACF,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,eAAe,WAAW,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAES,yBAAyB,CAClC,iBAAqC,EACrC,SAA4B,EAC5B,YAAqB,KAAK;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;QAC7D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,KAAK,CAAC;QACb,CAAC;QACD,IAAI,iBAAiB,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACvE,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACxD,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAC/B,KAAc,EACd,iBAA4C,EAC5C,SAA4B,EAC5B,YAAqB,KAAK;QAE1B,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,SAAS,KAAK,cAAc,CAAC,wBAAwB,EAAE,CAAC;YACxF,MAAM,UAAU,GAAG,IAAI,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;YAClE,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC9B,UAAU,CAAC,sBAAsB,CAAC;oBACjC,SAAS;oBACT,SAAS;iBACT,CAAC,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,0BAA0B,EAAE,EAAE,UAAU,CAAC,CAAC;gBAClF,kFAAkF;gBAClF,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC3B,MAAM,UAAU,CAAC;YAClB,CAAC;YACD,wGAAwG;YACxG,0GAA0G;YAC1G,cAAc;YACd,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE;gBACrD,OAAO,IAAI,eAAe,CAAC,kBAAkB,OAAO,EAAE,EAAE,CAAC,CAAC,uBAAuB,EAAE;oBAClF,CAAC,YAAY,CAAC,EAAE,IAAI;oBACpB,aAAa;iBACb,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,MAAM,QAAQ,CAAC;QAChB,CAAC;IACF,CAAC;IAEO,sBAAsB,CAC7B,iBAA4C;QAE5C,8FAA8F;QAC9F,sFAAsF;QACtF,iGAAiG;QACjG,IAAI,IAAI,CAAC,UAAU,IAAI,iBAAiB,IAAI,IAAI,CAAC,UAAU,KAAK,iBAAiB,EAAE,CAAC;YACnF,6EAA6E;YAC7E,yEAAyE;YACzE,OAAO,IAAI,iBAAiB,CAAC,gBAAgB,EAAE,cAAc,CAAC,wBAAwB,EAAE;gBACvF,aAAa;gBACb,WAAW,EAAE,iBAAiB;gBAC9B,WAAW,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAEO,kBAAkB,CAAC,KAAa;QACvC,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IAC3C,CAAC;CACD;AAED,MAAM,OAAO,0BAA2B,SAAQ,YAAY;IAG3D,YACoB,KAAsB,EACtB,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;QAE/C,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;QALjC,UAAK,GAAL,KAAK,CAAiB;QACtB,cAAS,GAAT,SAAS,CAAY;QACrB,WAAM,GAAN,MAAM,CAAqB;QAC3B,uBAAkB,GAAlB,kBAAkB,CAAU;QAN/B,wBAAmB,GAAG,IAAI,QAAQ,EAAQ,CAAC;QAS3D,2DAA2D;QAC3D,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAClD,CAAC;IAES,yBAAyB,CAClC,iBAAqC,EACrC,SAAoB,EACpB,YAAqB,KAAK;QAE1B,KAAK,CAAC,yBAAyB,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAEzE,8GAA8G;QAC9G,0GAA0G;QAC1G,oBAAoB;QACpB,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,+BAA+B;IAC/B,8DAA8D;IACvD,KAAK,CAAC,GAAG,CAAC,KAAa;QAC7B,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE9B,uDAAuD;QACvD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAChC,MAAM,GAAG,MAAM;iBACb,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBACf,iGAAiG;gBACjG,8FAA8F;gBAC9F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACzB,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;gBACpC,CAAC;gBACD,+DAA+D;gBAC/D,OAAO,KAAK,CAAC;YACd,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBAChB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvC,MAAM,KAAK,CAAC;YACb,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAC/B,GAAW,EACX,YAA8C,EAC9C,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,sGAAsG;QACtG,uGAAuG;QACvG,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC;QAEvD,IAAI,CAAC;YACJ,OAAO,MAAM,KAAK,CAAC,mBAAmB,CACrC,GAAG,EACH,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;YACF,8DAA8D;QAC/D,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACrB,+FAA+F;YAC/F,8EAA8E;YAC9E,8EAA8E;YAC9E,IAAI,SAAS,KAAK,aAAa,EAAE,CAAC;gBACjC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACxC,CAAC;YACD,IACC,SAAS,KAAK,aAAa;gBAC3B,sEAAsE;gBACtE,KAAK,CAAC,UAAU,GAAG,GAAG;gBACtB,sEAAsE;gBACtE,KAAK,CAAC,UAAU,GAAG,GAAG;gBACtB,SAAS,EACR,CAAC;gBACF,MAAM,KAAK,CAAC;YACb,CAAC;QACF,CAAC;QAED,gDAAgD;QAChD,yEAAyE;QACzE,wFAAwF;QAExF,gGAAgG;QAChG,wEAAwE;QACxE,+EAA+E;QAC/E,wGAAwG;QACxG,0BAA0B;QAC1B,MAAM,gBAAgB,CAAC,cAAc,CACpC,IAAI,CAAC,MAAM,EACX,EAAE,SAAS,EAAE,qBAAqB,EAAE,EACpC,KAAK,EAAE,KAAK,EAAE,EAAE;YACf,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,0BAA0B;YACjD,IAAI,KAAoC,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;gBAChD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBACvB,OAAO,CAAC,UAAU,CAAC,CAAC;gBACrB,CAAC,EAAE,KAAK,CAAC,CAAC;YACX,CAAC,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;gBAC9B,QAAQ;gBACR,kFAAkF;gBAClF,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;aACnE,CAAC,CAAC;YACH,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;gBACxB,KAAK,CAAC,MAAM,EAAE,CAAC;YAChB,CAAC;QACF,CAAC,EACD,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAC7C,CAAC;QACF,OAAO,KAAK,CAAC,mBAAmB,CAAI,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC;CACD;AAUD,MAAM,UAAU,yBAAyB,CACxC,iBAAkC,EAClC,kBAAuC,EACvC,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;IAE5B,MAAM,YAAY,GAAG,IAAI,0BAA0B,CAClD,iBAAiB,EACjB,SAAS,EACT,MAAM,EACN,kBAAkB,CAClB,CAAC;IACF,OAAO;QACN,KAAK,EAAE;YACN,GAAG,kBAAkB;YACrB,cAAc,EAAE,YAAY;SAC5B;QACD,YAAY;KACZ,CAAC;AACH,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, Deferred } from \"@fluidframework/core-utils/internal\";\nimport {\n\tLocationRedirectionError,\n\tNonRetryableError,\n\tRateLimiter,\n\tThrottlingError,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tICacheEntry,\n\tIEntry,\n\tIFileEntry,\n\tIOdspError,\n\tIOdspErrorAugmentations,\n\tIOdspResolvedUrl,\n\tIPersistedCache,\n\tOdspErrorTypes,\n\tmaximumCacheDurationMs,\n\tsnapshotKey,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tPerformanceEvent,\n\tisFluidError,\n\tloggerToMonitoringContext,\n\tnormalizeError,\n\twrapError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts.js\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic.js\";\nimport { INonPersistentCache, IOdspCache, IPersistedFileCache } from \"./odspCache.js\";\nimport { patchOdspResolvedUrl } from \"./odspLocationRedirection.js\";\nimport {\n\tIOdspResponse,\n\tfetchAndParseAsJSONHelper,\n\tfetchArray,\n\tfetchHelper,\n\tgetOdspResolvedUrl,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\n\n/**\n * @alpha\n */\nexport type FetchType =\n\t| \"blob\"\n\t| \"createBlob\"\n\t| \"createFile\"\n\t| \"joinSession\"\n\t| \"ops\"\n\t| \"test\"\n\t| \"snapshotTree\"\n\t| \"treesLatest\"\n\t| \"uploadSummary\"\n\t| \"push\"\n\t| \"versions\";\n\n/**\n * @alpha\n */\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n/**\n * In ODSP, the concept of \"epoch\" refers to binary updates to files. For example, this might include using\n * version restore, or if the user downloads a Fluid file and then uploads it again. These result in the epoch\n * value being incremented.\n *\n * The implications of these binary updates is that the Fluid state is disrupted: the sequence number might\n * go backwards, the data might be inconsistent with the latest state of collaboration, etc. As a result, it's\n * not safe to continue collaboration across an epoch change. We need to detect these epoch changes and\n * error out from the collaboration.\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 * @alpha\n */\nexport class EpochTracker implements IPersistedFileCache {\n\tprivate _fluidEpoch: string | undefined;\n\n\tprivate readonly snapshotCacheExpiryTimeoutMs: number;\n\tpublic readonly rateLimiter: RateLimiter;\n\tprivate readonly driverId = uuid();\n\t// This tracks the request number made by the driver instance.\n\tprivate networkCallNumber = 1;\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\t// Limits the max number of concurrent requests to 24.\n\t\tthis.rateLimiter = new RateLimiter(24);\n\n\t\t// Matches the TestOverride logic for the policy defined in odspDocumentStorageServiceBase.ts\n\t\tthis.snapshotCacheExpiryTimeoutMs = loggerToMonitoringContext(logger).config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache\",\n\t\t)\n\t\t\t? 0\n\t\t\t: maximumCacheDurationMs;\n\t}\n\n\t// public for UT purposes only!\n\tpublic setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal): void {\n\t\tassert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n\t\tthis._fluidEpoch = epoch;\n\n\t\tthis.logger.sendTelemetryEvent({\n\t\t\teventName: \"EpochLearnedFirstTime\",\n\t\t\tepoch,\n\t\t\tfetchType,\n\t\t\tfromCache,\n\t\t});\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\ttry {\n\t\t\t// Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst value: IVersionedValueWithEpoch = await this.cache.get(\n\t\t\t\tthis.fileEntryFromEntry(entry),\n\t\t\t);\n\t\t\t// Version mismatch between what the runtime expects and what it recieved.\n\t\t\t// The cached value should not be used\n\t\t\tif (value === undefined || value.version !== persistedCacheValueVersion) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tassert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n\t\t\tif (this._fluidEpoch === undefined) {\n\t\t\t\tthis.setEpoch(value.fluidEpoch, true, \"cache\");\n\t\t\t\t// Epoch mismatch, the cached value is considerably different from what the current state of\n\t\t\t\t// the runtime and should not be used\n\t\t\t} else if (this._fluidEpoch !== value.fluidEpoch) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately\n\t\t\t// expire all old caches that do not have cacheEntryTime\n\t\t\tif (entry.type === snapshotKey) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\t\tconst cacheTime = value.value?.cacheEntryTime;\n\t\t\t\tconst currentTime = Date.now();\n\t\t\t\tif (\n\t\t\t\t\tcacheTime === undefined ||\n\t\t\t\t\tcurrentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs\n\t\t\t\t) {\n\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"odspVersionsCacheExpired\",\n\t\t\t\t\t\tduration: currentTime - cacheTime,\n\t\t\t\t\t\tmaxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,\n\t\t\t\t\t});\n\t\t\t\t\tawait this.removeEntries();\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\treturn value.value;\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t// TODO: take a stronger type or `unknown`\n\t// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any\n\tpublic async put(entry: IEntry, value: any): Promise<void> {\n\t\tassert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n\t\t// For snapshots, the value should have the cacheEntryTime.\n\t\t// This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.\n\t\tif (entry.type === snapshotKey) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\tvalue.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n\t\t}\n\t\tconst data: IVersionedValueWithEpoch = {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tvalue,\n\t\t\tversion: persistedCacheValueVersion,\n\t\t\tfluidEpoch: this._fluidEpoch,\n\t\t};\n\t\treturn this.cache.put(this.fileEntryFromEntry(entry), data).catch((error) => {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n\t\t\tthrow error;\n\t\t});\n\t}\n\n\tpublic async removeEntries(): Promise<void> {\n\t\ttry {\n\t\t\treturn await this.cache.removeEntries(this.fileEntry);\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n\t\t}\n\t}\n\n\tpublic get fluidEpoch(): string | undefined {\n\t\treturn this._fluidEpoch;\n\t}\n\n\tpublic async validateEpoch(epoch: string | undefined, fetchType: FetchType): Promise<void> {\n\t\tassert(epoch !== undefined, 0x584 /* response should contain epoch */);\n\t\ttry {\n\t\t\tthis.validateEpochFromResponse(epoch, fetchType);\n\t\t} catch (error) {\n\t\t\tawait this.checkForEpochError(error, epoch, fetchType);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\treturn this.fetchCore<T>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchAndParseAsJSONHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetch(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<Response>> {\n\t\treturn this.fetchCore<Response>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate async fetchCore<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetcher: (url: string, fetchOptions: RequestInit) => Promise<IOdspResponse<T>>,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\tconst clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n\t\t// Add epoch in fetch request.\n\t\tthis.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n\t\tlet epochFromResponse: string | undefined;\n\t\treturn this.rateLimiter\n\t\t\t.schedule(async () => fetcher(url, fetchOptions))\n\t\t\t.then((response) => {\n\t\t\t\tepochFromResponse = response.headers.get(\"x-fluid-epoch\");\n\t\t\t\tthis.validateEpochFromResponse(epochFromResponse, fetchType);\n\t\t\t\tresponse.propsToLog.XRequestStatsHeader = clientCorrelationId;\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.catch(async (error) => {\n\t\t\t\t// Get the server epoch from error in case we don't have it as if undefined we won't be able\n\t\t\t\t// to mark it as epoch error.\n\t\t\t\tif (epochFromResponse === undefined) {\n\t\t\t\t\tepochFromResponse = (error as IOdspError).serverEpoch;\n\t\t\t\t}\n\t\t\t\tawait this.checkForEpochError(error, epochFromResponse, fetchType);\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\t// If the error is about location redirection, then we need to generate new resolved url with correct\n\t\t\t\t// location info.\n\t\t\t\tif (\n\t\t\t\t\tisFluidError(error) &&\n\t\t\t\t\terror.errorType === OdspErrorTypes.fileNotFoundOrAccessDeniedError\n\t\t\t\t) {\n\t\t\t\t\tconst redirectLocation = (error as IOdspErrorAugmentations).redirectLocation;\n\t\t\t\t\tif (redirectLocation !== undefined) {\n\t\t\t\t\t\tconst redirectUrl: IOdspResolvedUrl = patchOdspResolvedUrl(\n\t\t\t\t\t\t\tthis.fileEntry.resolvedUrl,\n\t\t\t\t\t\t\tredirectLocation,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst locationRedirectionError = new LocationRedirectionError(\n\t\t\t\t\t\t\terror.message,\n\t\t\t\t\t\t\tredirectUrl,\n\t\t\t\t\t\t\t{ driverVersion, redirectLocation },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlocationRedirectionError.addTelemetryProperties(error.getTelemetryProperties());\n\t\t\t\t\t\tthrow locationRedirectionError;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconst fluidError = normalizeError(error, {\n\t\t\t\t\tprops: { XRequestStatsHeader: clientCorrelationId },\n\t\t\t\t});\n\t\t\t\tthrow fluidError;\n\t\t\t});\n\t}\n\n\t/**\n\t * Api to fetch the response as it is for given request.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchArray(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<ArrayBuffer>> {\n\t\treturn this.fetchCore<ArrayBuffer>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchArray,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate addEpochInRequest(\n\t\tfetchOptions: RequestInit,\n\t\taddInBody: boolean,\n\t\tclientCorrelationId: string,\n\t): void {\n\t\tconst isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n\t\tif (addInBody) {\n\t\t\tconst headers: { [key: string]: string } = {};\n\t\t\theaders[\"X-RequestStats\"] = clientCorrelationId;\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\theaders[\"x-fluid-epoch\"] = this.fluidEpoch;\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\theaders[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n\t\t\t}\n\t\t\tthis.addParamInBody(fetchOptions, headers);\n\t\t} else {\n\t\t\tconst addHeader = (key: string, val: string): void => {\n\t\t\t\tfetchOptions.headers = {\n\t\t\t\t\t...fetchOptions.headers,\n\t\t\t\t};\n\t\t\t\tassert(\n\t\t\t\t\tfetchOptions.headers !== undefined,\n\t\t\t\t\t0x282 /* \"Headers should be present now\" */,\n\t\t\t\t);\n\t\t\t\tfetchOptions.headers[key] = val;\n\t\t\t};\n\t\t\taddHeader(\"X-RequestStats\", clientCorrelationId);\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\taddHeader(\"x-fluid-epoch\", this.fluidEpoch);\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\taddHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addParamInBody(fetchOptions: RequestInit, headers: { [key: string]: string }): void {\n\t\t// We use multi part form request for post body where we want to use this.\n\t\t// So extract the form boundary to mark the end of form.\n\t\tconst body = fetchOptions.body;\n\t\tassert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n\t\tconst splitBody = body.split(\"\\r\\n\");\n\t\tconst firstLine = splitBody.shift();\n\t\tassert(firstLine?.startsWith(\"--\") === true, 0x21e /* \"improper boundary format\" */);\n\t\tconst formParams = [firstLine];\n\t\tfor (const [key, value] of Object.entries(headers)) {\n\t\t\tformParams.push(`${key}: ${value}`);\n\t\t}\n\t\tfor (const value of splitBody) {\n\t\t\tformParams.push(value);\n\t\t}\n\t\tfetchOptions.body = formParams.join(\"\\r\\n\");\n\t}\n\n\tprivate formatClientCorrelationId(fetchReason?: string): string {\n\t\tconst items: string[] = [\n\t\t\t`driverId=${this.driverId}`,\n\t\t\t`RequestNumber=${this.networkCallNumber++}`,\n\t\t\t`driverVersion=${driverVersion}`,\n\t\t\t`isSummarizer=${this.clientIsSummarizer}`,\n\t\t];\n\t\tif (fetchReason !== undefined) {\n\t\t\titems.push(`fetchReason=${fetchReason}`);\n\t\t}\n\t\treturn items.join(\", \");\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tconst error = this.checkForEpochErrorCore(epochFromResponse);\n\t\tif (error !== undefined) {\n\t\t\tthrow error;\n\t\t}\n\t\tif (epochFromResponse !== undefined && this._fluidEpoch === undefined) {\n\t\t\tthis.setEpoch(epochFromResponse, fromCache, fetchType);\n\t\t}\n\t}\n\n\tprivate async checkForEpochError(\n\t\terror: unknown,\n\t\tepochFromResponse: string | null | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): Promise<void> {\n\t\tif (isFluidError(error) && error.errorType === OdspErrorTypes.fileOverwrittenInStorage) {\n\t\t\tconst epochError = this.checkForEpochErrorCore(epochFromResponse);\n\t\t\tif (epochError !== undefined) {\n\t\t\t\tepochError.addTelemetryProperties({\n\t\t\t\t\tfromCache,\n\t\t\t\t\tfetchType,\n\t\t\t\t});\n\t\t\t\tthis.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n\t\t\t\t// If the epoch mismatches, then clear all entries for such file entry from cache.\n\t\t\t\tawait this.removeEntries();\n\t\t\t\tthrow epochError;\n\t\t\t}\n\t\t\t// If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n\t\t\t// then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n\t\t\t// time is 1s.\n\t\t\tconst newError = wrapError(error, (message: string) => {\n\t\t\t\treturn new ThrottlingError(`Coherency 409: ${message}`, 1 /* retryAfterSeconds */, {\n\t\t\t\t\t[Odsp409Error]: true,\n\t\t\t\t\tdriverVersion,\n\t\t\t\t});\n\t\t\t});\n\t\t\tthrow newError;\n\t\t}\n\t}\n\n\tprivate checkForEpochErrorCore(\n\t\tepochFromResponse: string | null | undefined,\n\t): NonRetryableError<\"fileOverwrittenInStorage\"> | undefined {\n\t\t// If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n\t\t// initializes this value. Sometimes response does not contain epoch as it is still in\n\t\t// implementation phase at server side. In that case also, don't compare it with our epoch value.\n\t\tif (this.fluidEpoch && epochFromResponse && this.fluidEpoch !== epochFromResponse) {\n\t\t\t// This is similar in nature to how fluidEpochMismatchError (409) is handled.\n\t\t\t// Difference - client detected mismatch, instead of server detecting it.\n\t\t\treturn new NonRetryableError(\"Epoch mismatch\", OdspErrorTypes.fileOverwrittenInStorage, {\n\t\t\t\tdriverVersion,\n\t\t\t\tserverEpoch: epochFromResponse,\n\t\t\t\tclientEpoch: this.fluidEpoch,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate fileEntryFromEntry(entry: IEntry): ICacheEntry {\n\t\treturn { ...entry, file: this.fileEntry };\n\t}\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n\tprivate readonly treesLatestDeferral = new Deferred<void>();\n\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\tsuper(cache, fileEntry, logger, clientIsSummarizer);\n\t\t// Handles the rejected promise within treesLatestDeferral.\n\t\tthis.treesLatestDeferral.promise.catch(() => {});\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchType,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tsuper.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n\t\t// Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n\t\t// That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n\t\t// exploring a file.\n\t\tthis.treesLatestDeferral.resolve();\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\tlet result = super.get(entry);\n\n\t\t// equivalence of what happens in fetchAndParseAsJSON()\n\t\tif (entry.type === snapshotKey) {\n\t\t\tresult = result\n\t\t\t\t.then((value) => {\n\t\t\t\t\t// If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n\t\t\t\t\t// Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n\t\t\t\t\tif (value !== undefined) {\n\t\t\t\t\t\tthis.treesLatestDeferral.resolve();\n\t\t\t\t\t}\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\t\t\treturn value;\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\t// Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n\t\t// joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n\t\tconst completed = this.treesLatestDeferral.isCompleted;\n\n\t\ttry {\n\t\t\treturn await super.fetchAndParseAsJSON<T>(\n\t\t\t\turl,\n\t\t\t\tfetchOptions,\n\t\t\t\tfetchType,\n\t\t\t\taddInBody,\n\t\t\t\tfetchReason,\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t} catch (error: any) {\n\t\t\t// Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n\t\t\t// Similar, if getVersions failed, we should not do any further storage calls.\n\t\t\t// So treesLatest is the only call that can have parallel joinSession request.\n\t\t\tif (fetchType === \"treesLatest\") {\n\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tfetchType !== \"joinSession\" ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode < 401 ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode > 404 ||\n\t\t\t\tcompleted\n\t\t\t) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// It is joinSession failing with 401..404 error\n\t\t// Repeat after waiting for treeLatest succeeding (or fail if it failed).\n\t\t// No special handling after first call - if file has been deleted, then it's game over.\n\n\t\t// Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n\t\t// If we waited too long, we will log error event and proceed with call.\n\t\t// It may result in failure for user, but refreshing document would address it.\n\t\t// Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n\t\t// to unblock the process.\n\t\tawait PerformanceEvent.timedExecAsync(\n\t\t\tthis.logger,\n\t\t\t{ eventName: \"JoinSessionSyncWait\" },\n\t\t\tasync (event) => {\n\t\t\t\tconst timeoutRes = 51; // anything will work here\n\t\t\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t\t\tconst timeoutP = new Promise<number>((resolve) => {\n\t\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\t\tresolve(timeoutRes);\n\t\t\t\t\t}, 15000);\n\t\t\t\t});\n\t\t\t\tconst res = await Promise.race([\n\t\t\t\t\ttimeoutP,\n\t\t\t\t\t// cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n\t\t\t\t\tthis.treesLatestDeferral.promise.finally(() => clearTimeout(timer)),\n\t\t\t\t]);\n\t\t\t\tif (res === timeoutRes) {\n\t\t\t\t\tevent.cancel();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ start: true, end: true, cancel: \"generic\" },\n\t\t);\n\t\treturn super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n\t}\n}\n\n/**\n * @alpha\n */\nexport interface ICacheAndTracker {\n\tcache: IOdspCache;\n\tepochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n\tpersistedCacheArg: IPersistedCache,\n\tnonpersistentCache: INonPersistentCache,\n\tfileEntry: IFileEntry,\n\tlogger: ITelemetryLoggerExt,\n\tclientIsSummarizer?: boolean,\n): ICacheAndTracker {\n\tconst epochTracker = new EpochTrackerWithRedemption(\n\t\tpersistedCacheArg,\n\t\tfileEntry,\n\t\tlogger,\n\t\tclientIsSummarizer,\n\t);\n\treturn {\n\t\tcache: {\n\t\t\t...nonpersistentCache,\n\t\t\tpersistedCache: epochTracker,\n\t\t},\n\t\tepochTracker,\n\t};\n}\n"]}
1
+ {"version":3,"file":"epochTracker.js","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EACN,wBAAwB,EACxB,iBAAiB,EACjB,WAAW,EACX,eAAe,GACf,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAQN,cAAc,EACd,sBAAsB,EACtB,WAAW,EACX,6BAA6B,GAC7B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,gBAAgB,EAChB,YAAY,EACZ,yBAAyB,EACzB,cAAc,EACd,SAAS,GACT,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EAA4B,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAEN,yBAAyB,EACzB,UAAU,EACV,WAAW,EACX,kBAAkB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAuBlE,MAAM,CAAC,MAAM,YAAY,GAAG,cAAc,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,YAAY;IAQxB,YACoB,KAAsB,EACtB,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;QAH5B,UAAK,GAAL,KAAK,CAAiB;QACtB,cAAS,GAAT,SAAS,CAAY;QACrB,WAAM,GAAN,MAAM,CAAqB;QAC3B,uBAAkB,GAAlB,kBAAkB,CAAU;QAP/B,aAAQ,GAAG,IAAI,EAAE,CAAC;QACnC,8DAA8D;QACtD,sBAAiB,GAAG,CAAC,CAAC;QAO7B,sDAAsD;QACtD,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;QAEvC,6FAA6F;QAC7F,IAAI,CAAC,4BAA4B,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,UAAU,CACtF,qDAAqD,CACrD;YACA,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,sBAAsB,CAAC;IAC3B,CAAC;IAED,+BAA+B;IACxB,QAAQ,CAAC,KAAa,EAAE,SAAkB,EAAE,SAA4B;QAC9E,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAEzB,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAC9B,SAAS,EAAE,uBAAuB;YAClC,KAAK;YACL,SAAS;YACT,SAAS;SACT,CAAC,CAAC;IACJ,CAAC;IAED,+BAA+B;IAC/B,8DAA8D;IACvD,KAAK,CAAC,GAAG,CAAC,KAAa;QAC7B,IAAI,CAAC;YACJ,8FAA8F;YAC9F,mEAAmE;YACnE,MAAM,KAAK,GAA6B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAC3D,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAC9B,CAAC;YACF,0EAA0E;YAC1E,sCAAsC;YACtC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,0BAA0B,EAAE,CAAC;gBACzE,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACrF,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC/C,4FAA4F;gBAC5F,qCAAqC;YACtC,CAAC;iBAAM,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC;gBAClD,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,6FAA6F;YAC7F,wDAAwD;YACxD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,KAAK,6BAA6B,EAAE,CAAC;gBAChF,+GAA+G;gBAC/G,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC;gBAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC/B,IACC,SAAS,KAAK,SAAS;oBACvB,WAAW,GAAG,SAAS,IAAI,IAAI,CAAC,4BAA4B,EAC3D,CAAC;oBACF,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;wBAC9B,SAAS,EAAE,0BAA0B;wBACrC,QAAQ,EAAE,WAAW,GAAG,SAAS;wBACjC,aAAa,EAAE,IAAI,CAAC,4BAA4B;qBAChD,CAAC,CAAC;oBACH,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC3B,OAAO,SAAS,CAAC;gBAClB,CAAC;YACF,CAAC;YACD,+DAA+D;YAC/D,OAAO,KAAK,CAAC,KAAK,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACtF,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IAED,0CAA0C;IAC1C,iHAAiH;IAC1G,KAAK,CAAC,GAAG,CAAC,KAAa,EAAE,KAAU;QACzC,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC/D,2DAA2D;QAC3D,iFAAiF;QACjF,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,KAAK,6BAA6B,EAAE,CAAC;YAChF,+GAA+G;YAC/G,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3D,CAAC;QACD,MAAM,IAAI,GAA6B;YACtC,mEAAmE;YACnE,KAAK;YACL,OAAO,EAAE,0BAA0B;YACnC,UAAU,EAAE,IAAI,CAAC,WAAW;SAC5B,CAAC;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC3E,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACpF,MAAM,KAAK,CAAC;QACb,CAAC,CAAC,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,aAAa;QACzB,IAAI,CAAC;YACJ,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,EAAE,KAAK,CAAC,CAAC;QACxE,CAAC;IACF,CAAC;IAED,IAAW,UAAU;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,KAAyB,EAAE,SAAoB;QACzE,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvE,IAAI,CAAC;YACJ,IAAI,CAAC,yBAAyB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,mBAAmB,CAC/B,GAAW,EACX,YAAyB,EACzB,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,yBAAyB,EACzB,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,KAAK,CACjB,GAAW,EACX,YAAyB,EACzB,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,WAAW,EACX,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS,CACtB,GAAW,EACX,YAAyB,EACzB,OAA8E,EAC9E,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,MAAM,mBAAmB,GAAG,IAAI,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC;QACxE,8BAA8B;QAC9B,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;QACrE,IAAI,iBAAqC,CAAC;QAC1C,OAAO,IAAI,CAAC,WAAW;aACrB,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;aAChD,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClB,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC1D,IAAI,CAAC,yBAAyB,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;YAC7D,QAAQ,CAAC,UAAU,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;YAC9D,OAAO,QAAQ,CAAC;QACjB,CAAC,CAAC;aACD,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACtB,4FAA4F;YAC5F,6BAA6B;YAC7B,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACrC,iBAAiB,GAAI,KAAoB,CAAC,WAAW,CAAC;YACvD,CAAC;YACD,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC;YACnE,MAAM,KAAK,CAAC;QACb,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,qGAAqG;YACrG,iBAAiB;YACjB,IACC,YAAY,CAAC,KAAK,CAAC;gBACnB,KAAK,CAAC,SAAS,KAAK,cAAc,CAAC,+BAA+B,EACjE,CAAC;gBACF,MAAM,gBAAgB,GAAI,KAAiC,CAAC,gBAAgB,CAAC;gBAC7E,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;oBACpC,MAAM,WAAW,GAAqB,oBAAoB,CACzD,IAAI,CAAC,SAAS,CAAC,WAAW,EAC1B,gBAAgB,CAChB,CAAC;oBACF,MAAM,wBAAwB,GAAG,IAAI,wBAAwB,CAC5D,KAAK,CAAC,OAAO,EACb,WAAW,EACX,EAAE,aAAa,EAAE,gBAAgB,EAAE,CACnC,CAAC;oBACF,wBAAwB,CAAC,sBAAsB,CAAC,KAAK,CAAC,sBAAsB,EAAE,CAAC,CAAC;oBAChF,MAAM,wBAAwB,CAAC;gBAChC,CAAC;YACF,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,EAAE;gBACxC,KAAK,EAAE,EAAE,mBAAmB,EAAE,mBAAmB,EAAE;aACnD,CAAC,CAAC;YACH,MAAM,UAAU,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,UAAU,CACtB,GAAW,EACX,YAA8C,EAC9C,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,OAAO,IAAI,CAAC,SAAS,CACpB,GAAG,EACH,YAAY,EACZ,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;IACH,CAAC;IAEO,iBAAiB,CACxB,YAAyB,EACzB,SAAkB,EAClB,mBAA2B;QAE3B,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,iBAAiB,CAAC;QAC3F,IAAI,SAAS,EAAE,CAAC;YACf,MAAM,OAAO,GAA8B,EAAE,CAAC;YAC9C,OAAO,CAAC,gBAAgB,CAAC,GAAG,mBAAmB,CAAC;YAChD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACnC,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC5C,CAAC;YACD,IAAI,iBAAiB,EAAE,CAAC;gBACvB,OAAO,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YACjF,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACP,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,GAAW,EAAQ,EAAE;gBACpD,YAAY,CAAC,OAAO,GAAG;oBACtB,GAAG,YAAY,CAAC,OAAO;iBACvB,CAAC;gBACF,MAAM,CACL,YAAY,CAAC,OAAO,KAAK,SAAS,EAClC,KAAK,CAAC,qCAAqC,CAC3C,CAAC;gBACF,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YACjC,CAAC,CAAC;YACF,SAAS,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACnC,SAAS,CAAC,eAAe,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7C,CAAC;YACD,IAAI,iBAAiB,EAAE,CAAC;gBACvB,SAAS,CAAC,qBAAqB,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC;YAClF,CAAC;QACF,CAAC;IACF,CAAC;IAEO,cAAc,CAAC,YAAyB,EAAE,OAAkC;QACnF,0EAA0E;QAC1E,wDAAwD;QACxD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;QAC/B,MAAM,CAAC,OAAO,IAAI,KAAK,QAAQ,EAAE,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACnE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACrF,MAAM,UAAU,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACpD,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC/B,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,YAAY,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAEO,yBAAyB,CAAC,WAAoB;QACrD,MAAM,KAAK,GAAa;YACvB,YAAY,IAAI,CAAC,QAAQ,EAAE;YAC3B,iBAAiB,IAAI,CAAC,iBAAiB,EAAE,EAAE;YAC3C,iBAAiB,aAAa,EAAE;YAChC,gBAAgB,IAAI,CAAC,kBAAkB,EAAE;SACzC,CAAC;QACF,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,eAAe,WAAW,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAES,yBAAyB,CAClC,iBAAqC,EACrC,SAA4B,EAC5B,YAAqB,KAAK;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;QAC7D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,KAAK,CAAC;QACb,CAAC;QACD,IAAI,iBAAiB,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACvE,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACxD,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAC/B,KAAc,EACd,iBAA4C,EAC5C,SAA4B,EAC5B,YAAqB,KAAK;QAE1B,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,SAAS,KAAK,cAAc,CAAC,wBAAwB,EAAE,CAAC;YACxF,MAAM,UAAU,GAAG,IAAI,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;YAClE,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC9B,UAAU,CAAC,sBAAsB,CAAC;oBACjC,SAAS;oBACT,SAAS;iBACT,CAAC,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,0BAA0B,EAAE,EAAE,UAAU,CAAC,CAAC;gBAClF,kFAAkF;gBAClF,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC3B,MAAM,UAAU,CAAC;YAClB,CAAC;YACD,wGAAwG;YACxG,0GAA0G;YAC1G,cAAc;YACd,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE;gBACrD,OAAO,IAAI,eAAe,CAAC,kBAAkB,OAAO,EAAE,EAAE,CAAC,CAAC,uBAAuB,EAAE;oBAClF,CAAC,YAAY,CAAC,EAAE,IAAI;oBACpB,aAAa;iBACb,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,MAAM,QAAQ,CAAC;QAChB,CAAC;IACF,CAAC;IAEO,sBAAsB,CAC7B,iBAA4C;QAE5C,8FAA8F;QAC9F,sFAAsF;QACtF,iGAAiG;QACjG,IAAI,IAAI,CAAC,UAAU,IAAI,iBAAiB,IAAI,IAAI,CAAC,UAAU,KAAK,iBAAiB,EAAE,CAAC;YACnF,6EAA6E;YAC7E,yEAAyE;YACzE,OAAO,IAAI,iBAAiB,CAAC,gBAAgB,EAAE,cAAc,CAAC,wBAAwB,EAAE;gBACvF,aAAa;gBACb,WAAW,EAAE,iBAAiB;gBAC9B,WAAW,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAEO,kBAAkB,CAAC,KAAa;QACvC,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IAC3C,CAAC;CACD;AAED,MAAM,OAAO,0BAA2B,SAAQ,YAAY;IAG3D,YACoB,KAAsB,EACtB,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;QAE/C,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;QALjC,UAAK,GAAL,KAAK,CAAiB;QACtB,cAAS,GAAT,SAAS,CAAY;QACrB,WAAM,GAAN,MAAM,CAAqB;QAC3B,uBAAkB,GAAlB,kBAAkB,CAAU;QAN/B,wBAAmB,GAAG,IAAI,QAAQ,EAAQ,CAAC;QAS3D,2DAA2D;QAC3D,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAClD,CAAC;IAES,yBAAyB,CAClC,iBAAqC,EACrC,SAAoB,EACpB,YAAqB,KAAK;QAE1B,KAAK,CAAC,yBAAyB,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAEzE,8GAA8G;QAC9G,0GAA0G;QAC1G,oBAAoB;QACpB,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,+BAA+B;IAC/B,8DAA8D;IACvD,KAAK,CAAC,GAAG,CAAC,KAAa;QAC7B,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE9B,uDAAuD;QACvD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,KAAK,6BAA6B,EAAE,CAAC;YAChF,MAAM,GAAG,MAAM;iBACb,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBACf,iGAAiG;gBACjG,8FAA8F;gBAC9F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACzB,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;gBACpC,CAAC;gBACD,+DAA+D;gBAC/D,OAAO,KAAK,CAAC;YACd,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBAChB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvC,MAAM,KAAK,CAAC;YACb,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAC/B,GAAW,EACX,YAA8C,EAC9C,SAAoB,EACpB,YAAqB,KAAK,EAC1B,WAAoB;QAEpB,sGAAsG;QACtG,uGAAuG;QACvG,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC;QAEvD,IAAI,CAAC;YACJ,OAAO,MAAM,KAAK,CAAC,mBAAmB,CACrC,GAAG,EACH,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,CACX,CAAC;YACF,8DAA8D;QAC/D,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACrB,+FAA+F;YAC/F,8EAA8E;YAC9E,8EAA8E;YAC9E,IAAI,SAAS,KAAK,aAAa,EAAE,CAAC;gBACjC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACxC,CAAC;YACD,IACC,SAAS,KAAK,aAAa;gBAC3B,sEAAsE;gBACtE,KAAK,CAAC,UAAU,GAAG,GAAG;gBACtB,sEAAsE;gBACtE,KAAK,CAAC,UAAU,GAAG,GAAG;gBACtB,SAAS,EACR,CAAC;gBACF,MAAM,KAAK,CAAC;YACb,CAAC;QACF,CAAC;QAED,gDAAgD;QAChD,yEAAyE;QACzE,wFAAwF;QAExF,gGAAgG;QAChG,wEAAwE;QACxE,+EAA+E;QAC/E,wGAAwG;QACxG,0BAA0B;QAC1B,MAAM,gBAAgB,CAAC,cAAc,CACpC,IAAI,CAAC,MAAM,EACX,EAAE,SAAS,EAAE,qBAAqB,EAAE,EACpC,KAAK,EAAE,KAAK,EAAE,EAAE;YACf,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,0BAA0B;YACjD,IAAI,KAAoC,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;gBAChD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBACvB,OAAO,CAAC,UAAU,CAAC,CAAC;gBACrB,CAAC,EAAE,KAAK,CAAC,CAAC;YACX,CAAC,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;gBAC9B,QAAQ;gBACR,kFAAkF;gBAClF,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;aACnE,CAAC,CAAC;YACH,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;gBACxB,KAAK,CAAC,MAAM,EAAE,CAAC;YAChB,CAAC;QACF,CAAC,EACD,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAC7C,CAAC;QACF,OAAO,KAAK,CAAC,mBAAmB,CAAI,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC;CACD;AAUD,MAAM,UAAU,yBAAyB,CACxC,iBAAkC,EAClC,kBAAuC,EACvC,SAAqB,EACrB,MAA2B,EAC3B,kBAA4B;IAE5B,MAAM,YAAY,GAAG,IAAI,0BAA0B,CAClD,iBAAiB,EACjB,SAAS,EACT,MAAM,EACN,kBAAkB,CAClB,CAAC;IACF,OAAO;QACN,KAAK,EAAE;YACN,GAAG,kBAAkB;YACrB,cAAc,EAAE,YAAY;SAC5B;QACD,YAAY;KACZ,CAAC;AACH,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, Deferred } from \"@fluidframework/core-utils/internal\";\nimport {\n\tLocationRedirectionError,\n\tNonRetryableError,\n\tRateLimiter,\n\tThrottlingError,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tICacheEntry,\n\tIEntry,\n\tIFileEntry,\n\tIOdspError,\n\tIOdspErrorAugmentations,\n\tIOdspResolvedUrl,\n\tIPersistedCache,\n\tOdspErrorTypes,\n\tmaximumCacheDurationMs,\n\tsnapshotKey,\n\tsnapshotWithLoadingGroupIdKey,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tPerformanceEvent,\n\tisFluidError,\n\tloggerToMonitoringContext,\n\tnormalizeError,\n\twrapError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts.js\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic.js\";\nimport { INonPersistentCache, IOdspCache, IPersistedFileCache } from \"./odspCache.js\";\nimport { patchOdspResolvedUrl } from \"./odspLocationRedirection.js\";\nimport {\n\tIOdspResponse,\n\tfetchAndParseAsJSONHelper,\n\tfetchArray,\n\tfetchHelper,\n\tgetOdspResolvedUrl,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\n\n/**\n * @alpha\n */\nexport type FetchType =\n\t| \"blob\"\n\t| \"createBlob\"\n\t| \"createFile\"\n\t| \"joinSession\"\n\t| \"ops\"\n\t| \"test\"\n\t| \"snapshotTree\"\n\t| \"treesLatest\"\n\t| \"uploadSummary\"\n\t| \"push\"\n\t| \"versions\";\n\n/**\n * @alpha\n */\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n/**\n * In ODSP, the concept of \"epoch\" refers to binary updates to files. For example, this might include using\n * version restore, or if the user downloads a Fluid file and then uploads it again. These result in the epoch\n * value being incremented.\n *\n * The implications of these binary updates is that the Fluid state is disrupted: the sequence number might\n * go backwards, the data might be inconsistent with the latest state of collaboration, etc. As a result, it's\n * not safe to continue collaboration across an epoch change. We need to detect these epoch changes and\n * error out from the collaboration.\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 * @alpha\n */\nexport class EpochTracker implements IPersistedFileCache {\n\tprivate _fluidEpoch: string | undefined;\n\n\tprivate readonly snapshotCacheExpiryTimeoutMs: number;\n\tpublic readonly rateLimiter: RateLimiter;\n\tprivate readonly driverId = uuid();\n\t// This tracks the request number made by the driver instance.\n\tprivate networkCallNumber = 1;\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\t// Limits the max number of concurrent requests to 24.\n\t\tthis.rateLimiter = new RateLimiter(24);\n\n\t\t// Matches the TestOverride logic for the policy defined in odspDocumentStorageServiceBase.ts\n\t\tthis.snapshotCacheExpiryTimeoutMs = loggerToMonitoringContext(logger).config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache\",\n\t\t)\n\t\t\t? 0\n\t\t\t: maximumCacheDurationMs;\n\t}\n\n\t// public for UT purposes only!\n\tpublic setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal): void {\n\t\tassert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n\t\tthis._fluidEpoch = epoch;\n\n\t\tthis.logger.sendTelemetryEvent({\n\t\t\teventName: \"EpochLearnedFirstTime\",\n\t\t\tepoch,\n\t\t\tfetchType,\n\t\t\tfromCache,\n\t\t});\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\ttry {\n\t\t\t// Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst value: IVersionedValueWithEpoch = await this.cache.get(\n\t\t\t\tthis.fileEntryFromEntry(entry),\n\t\t\t);\n\t\t\t// Version mismatch between what the runtime expects and what it recieved.\n\t\t\t// The cached value should not be used\n\t\t\tif (value === undefined || value.version !== persistedCacheValueVersion) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tassert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n\t\t\tif (this._fluidEpoch === undefined) {\n\t\t\t\tthis.setEpoch(value.fluidEpoch, true, \"cache\");\n\t\t\t\t// Epoch mismatch, the cached value is considerably different from what the current state of\n\t\t\t\t// the runtime and should not be used\n\t\t\t} else if (this._fluidEpoch !== value.fluidEpoch) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately\n\t\t\t// expire all old caches that do not have cacheEntryTime\n\t\t\tif (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\t\tconst cacheTime = value.value?.cacheEntryTime;\n\t\t\t\tconst currentTime = Date.now();\n\t\t\t\tif (\n\t\t\t\t\tcacheTime === undefined ||\n\t\t\t\t\tcurrentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs\n\t\t\t\t) {\n\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"odspVersionsCacheExpired\",\n\t\t\t\t\t\tduration: currentTime - cacheTime,\n\t\t\t\t\t\tmaxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,\n\t\t\t\t\t});\n\t\t\t\t\tawait this.removeEntries();\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\treturn value.value;\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t// TODO: take a stronger type or `unknown`\n\t// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any\n\tpublic async put(entry: IEntry, value: any): Promise<void> {\n\t\tassert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n\t\t// For snapshots, the value should have the cacheEntryTime.\n\t\t// This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.\n\t\tif (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n\t\t\tvalue.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n\t\t}\n\t\tconst data: IVersionedValueWithEpoch = {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tvalue,\n\t\t\tversion: persistedCacheValueVersion,\n\t\t\tfluidEpoch: this._fluidEpoch,\n\t\t};\n\t\treturn this.cache.put(this.fileEntryFromEntry(entry), data).catch((error) => {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n\t\t\tthrow error;\n\t\t});\n\t}\n\n\tpublic async removeEntries(): Promise<void> {\n\t\ttry {\n\t\t\treturn await this.cache.removeEntries(this.fileEntry);\n\t\t} catch (error) {\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n\t\t}\n\t}\n\n\tpublic get fluidEpoch(): string | undefined {\n\t\treturn this._fluidEpoch;\n\t}\n\n\tpublic async validateEpoch(epoch: string | undefined, fetchType: FetchType): Promise<void> {\n\t\tassert(epoch !== undefined, 0x584 /* response should contain epoch */);\n\t\ttry {\n\t\t\tthis.validateEpochFromResponse(epoch, fetchType);\n\t\t} catch (error) {\n\t\t\tawait this.checkForEpochError(error, epoch, fetchType);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\treturn this.fetchCore<T>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchAndParseAsJSONHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\t/**\n\t * Api to fetch the response for given request and parse it as json.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetch(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<Response>> {\n\t\treturn this.fetchCore<Response>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchHelper,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate async fetchCore<T>(\n\t\turl: string,\n\t\tfetchOptions: RequestInit,\n\t\tfetcher: (url: string, fetchOptions: RequestInit) => Promise<IOdspResponse<T>>,\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\tconst clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n\t\t// Add epoch in fetch request.\n\t\tthis.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n\t\tlet epochFromResponse: string | undefined;\n\t\treturn this.rateLimiter\n\t\t\t.schedule(async () => fetcher(url, fetchOptions))\n\t\t\t.then((response) => {\n\t\t\t\tepochFromResponse = response.headers.get(\"x-fluid-epoch\");\n\t\t\t\tthis.validateEpochFromResponse(epochFromResponse, fetchType);\n\t\t\t\tresponse.propsToLog.XRequestStatsHeader = clientCorrelationId;\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.catch(async (error) => {\n\t\t\t\t// Get the server epoch from error in case we don't have it as if undefined we won't be able\n\t\t\t\t// to mark it as epoch error.\n\t\t\t\tif (epochFromResponse === undefined) {\n\t\t\t\t\tepochFromResponse = (error as IOdspError).serverEpoch;\n\t\t\t\t}\n\t\t\t\tawait this.checkForEpochError(error, epochFromResponse, fetchType);\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\t// If the error is about location redirection, then we need to generate new resolved url with correct\n\t\t\t\t// location info.\n\t\t\t\tif (\n\t\t\t\t\tisFluidError(error) &&\n\t\t\t\t\terror.errorType === OdspErrorTypes.fileNotFoundOrAccessDeniedError\n\t\t\t\t) {\n\t\t\t\t\tconst redirectLocation = (error as IOdspErrorAugmentations).redirectLocation;\n\t\t\t\t\tif (redirectLocation !== undefined) {\n\t\t\t\t\t\tconst redirectUrl: IOdspResolvedUrl = patchOdspResolvedUrl(\n\t\t\t\t\t\t\tthis.fileEntry.resolvedUrl,\n\t\t\t\t\t\t\tredirectLocation,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst locationRedirectionError = new LocationRedirectionError(\n\t\t\t\t\t\t\terror.message,\n\t\t\t\t\t\t\tredirectUrl,\n\t\t\t\t\t\t\t{ driverVersion, redirectLocation },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlocationRedirectionError.addTelemetryProperties(error.getTelemetryProperties());\n\t\t\t\t\t\tthrow locationRedirectionError;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconst fluidError = normalizeError(error, {\n\t\t\t\t\tprops: { XRequestStatsHeader: clientCorrelationId },\n\t\t\t\t});\n\t\t\t\tthrow fluidError;\n\t\t\t});\n\t}\n\n\t/**\n\t * Api to fetch the response as it is for given request.\n\t * @param url - url of the request\n\t * @param fetchOptions - fetch options for request containing body, headers etc.\n\t * @param fetchType - method for which fetch is called.\n\t * @param addInBody - Pass True if caller wants to add epoch in post body.\n\t * @param fetchReason - fetch reason to add to the request.\n\t */\n\tpublic async fetchArray(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<ArrayBuffer>> {\n\t\treturn this.fetchCore<ArrayBuffer>(\n\t\t\turl,\n\t\t\tfetchOptions,\n\t\t\tfetchArray,\n\t\t\tfetchType,\n\t\t\taddInBody,\n\t\t\tfetchReason,\n\t\t);\n\t}\n\n\tprivate addEpochInRequest(\n\t\tfetchOptions: RequestInit,\n\t\taddInBody: boolean,\n\t\tclientCorrelationId: string,\n\t): void {\n\t\tconst isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n\t\tif (addInBody) {\n\t\t\tconst headers: { [key: string]: string } = {};\n\t\t\theaders[\"X-RequestStats\"] = clientCorrelationId;\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\theaders[\"x-fluid-epoch\"] = this.fluidEpoch;\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\theaders[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n\t\t\t}\n\t\t\tthis.addParamInBody(fetchOptions, headers);\n\t\t} else {\n\t\t\tconst addHeader = (key: string, val: string): void => {\n\t\t\t\tfetchOptions.headers = {\n\t\t\t\t\t...fetchOptions.headers,\n\t\t\t\t};\n\t\t\t\tassert(\n\t\t\t\t\tfetchOptions.headers !== undefined,\n\t\t\t\t\t0x282 /* \"Headers should be present now\" */,\n\t\t\t\t);\n\t\t\t\tfetchOptions.headers[key] = val;\n\t\t\t};\n\t\t\taddHeader(\"X-RequestStats\", clientCorrelationId);\n\t\t\tif (this.fluidEpoch !== undefined) {\n\t\t\t\taddHeader(\"x-fluid-epoch\", this.fluidEpoch);\n\t\t\t}\n\t\t\tif (isClpCompliantApp) {\n\t\t\t\taddHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addParamInBody(fetchOptions: RequestInit, headers: { [key: string]: string }): void {\n\t\t// We use multi part form request for post body where we want to use this.\n\t\t// So extract the form boundary to mark the end of form.\n\t\tconst body = fetchOptions.body;\n\t\tassert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n\t\tconst splitBody = body.split(\"\\r\\n\");\n\t\tconst firstLine = splitBody.shift();\n\t\tassert(firstLine?.startsWith(\"--\") === true, 0x21e /* \"improper boundary format\" */);\n\t\tconst formParams = [firstLine];\n\t\tfor (const [key, value] of Object.entries(headers)) {\n\t\t\tformParams.push(`${key}: ${value}`);\n\t\t}\n\t\tfor (const value of splitBody) {\n\t\t\tformParams.push(value);\n\t\t}\n\t\tfetchOptions.body = formParams.join(\"\\r\\n\");\n\t}\n\n\tprivate formatClientCorrelationId(fetchReason?: string): string {\n\t\tconst items: string[] = [\n\t\t\t`driverId=${this.driverId}`,\n\t\t\t`RequestNumber=${this.networkCallNumber++}`,\n\t\t\t`driverVersion=${driverVersion}`,\n\t\t\t`isSummarizer=${this.clientIsSummarizer}`,\n\t\t];\n\t\tif (fetchReason !== undefined) {\n\t\t\titems.push(`fetchReason=${fetchReason}`);\n\t\t}\n\t\treturn items.join(\", \");\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tconst error = this.checkForEpochErrorCore(epochFromResponse);\n\t\tif (error !== undefined) {\n\t\t\tthrow error;\n\t\t}\n\t\tif (epochFromResponse !== undefined && this._fluidEpoch === undefined) {\n\t\t\tthis.setEpoch(epochFromResponse, fromCache, fetchType);\n\t\t}\n\t}\n\n\tprivate async checkForEpochError(\n\t\terror: unknown,\n\t\tepochFromResponse: string | null | undefined,\n\t\tfetchType: FetchTypeInternal,\n\t\tfromCache: boolean = false,\n\t): Promise<void> {\n\t\tif (isFluidError(error) && error.errorType === OdspErrorTypes.fileOverwrittenInStorage) {\n\t\t\tconst epochError = this.checkForEpochErrorCore(epochFromResponse);\n\t\t\tif (epochError !== undefined) {\n\t\t\t\tepochError.addTelemetryProperties({\n\t\t\t\t\tfromCache,\n\t\t\t\t\tfetchType,\n\t\t\t\t});\n\t\t\t\tthis.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n\t\t\t\t// If the epoch mismatches, then clear all entries for such file entry from cache.\n\t\t\t\tawait this.removeEntries();\n\t\t\t\tthrow epochError;\n\t\t\t}\n\t\t\t// If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n\t\t\t// then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n\t\t\t// time is 1s.\n\t\t\tconst newError = wrapError(error, (message: string) => {\n\t\t\t\treturn new ThrottlingError(`Coherency 409: ${message}`, 1 /* retryAfterSeconds */, {\n\t\t\t\t\t[Odsp409Error]: true,\n\t\t\t\t\tdriverVersion,\n\t\t\t\t});\n\t\t\t});\n\t\t\tthrow newError;\n\t\t}\n\t}\n\n\tprivate checkForEpochErrorCore(\n\t\tepochFromResponse: string | null | undefined,\n\t): NonRetryableError<\"fileOverwrittenInStorage\"> | undefined {\n\t\t// If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n\t\t// initializes this value. Sometimes response does not contain epoch as it is still in\n\t\t// implementation phase at server side. In that case also, don't compare it with our epoch value.\n\t\tif (this.fluidEpoch && epochFromResponse && this.fluidEpoch !== epochFromResponse) {\n\t\t\t// This is similar in nature to how fluidEpochMismatchError (409) is handled.\n\t\t\t// Difference - client detected mismatch, instead of server detecting it.\n\t\t\treturn new NonRetryableError(\"Epoch mismatch\", OdspErrorTypes.fileOverwrittenInStorage, {\n\t\t\t\tdriverVersion,\n\t\t\t\tserverEpoch: epochFromResponse,\n\t\t\t\tclientEpoch: this.fluidEpoch,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate fileEntryFromEntry(entry: IEntry): ICacheEntry {\n\t\treturn { ...entry, file: this.fileEntry };\n\t}\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n\tprivate readonly treesLatestDeferral = new Deferred<void>();\n\n\tconstructor(\n\t\tprotected readonly cache: IPersistedCache,\n\t\tprotected readonly fileEntry: IFileEntry,\n\t\tprotected readonly logger: ITelemetryLoggerExt,\n\t\tprotected readonly clientIsSummarizer?: boolean,\n\t) {\n\t\tsuper(cache, fileEntry, logger, clientIsSummarizer);\n\t\t// Handles the rejected promise within treesLatestDeferral.\n\t\tthis.treesLatestDeferral.promise.catch(() => {});\n\t}\n\n\tprotected validateEpochFromResponse(\n\t\tepochFromResponse: string | undefined,\n\t\tfetchType: FetchType,\n\t\tfromCache: boolean = false,\n\t): void {\n\t\tsuper.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n\t\t// Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n\t\t// That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n\t\t// exploring a file.\n\t\tthis.treesLatestDeferral.resolve();\n\t}\n\n\t// TODO: return a stronger type\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic async get(entry: IEntry): Promise<any> {\n\t\tlet result = super.get(entry);\n\n\t\t// equivalence of what happens in fetchAndParseAsJSON()\n\t\tif (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {\n\t\t\tresult = result\n\t\t\t\t.then((value) => {\n\t\t\t\t\t// If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n\t\t\t\t\t// Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n\t\t\t\t\tif (value !== undefined) {\n\t\t\t\t\t\tthis.treesLatestDeferral.resolve();\n\t\t\t\t\t}\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\t\t\treturn value;\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic async fetchAndParseAsJSON<T>(\n\t\turl: string,\n\t\tfetchOptions: { [index: string]: RequestInit },\n\t\tfetchType: FetchType,\n\t\taddInBody: boolean = false,\n\t\tfetchReason?: string,\n\t): Promise<IOdspResponse<T>> {\n\t\t// Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n\t\t// joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n\t\tconst completed = this.treesLatestDeferral.isCompleted;\n\n\t\ttry {\n\t\t\treturn await super.fetchAndParseAsJSON<T>(\n\t\t\t\turl,\n\t\t\t\tfetchOptions,\n\t\t\t\tfetchType,\n\t\t\t\taddInBody,\n\t\t\t\tfetchReason,\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t} catch (error: any) {\n\t\t\t// Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n\t\t\t// Similar, if getVersions failed, we should not do any further storage calls.\n\t\t\t// So treesLatest is the only call that can have parallel joinSession request.\n\t\t\tif (fetchType === \"treesLatest\") {\n\t\t\t\tthis.treesLatestDeferral.reject(error);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tfetchType !== \"joinSession\" ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode < 401 ||\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\t\terror.statusCode > 404 ||\n\t\t\t\tcompleted\n\t\t\t) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// It is joinSession failing with 401..404 error\n\t\t// Repeat after waiting for treeLatest succeeding (or fail if it failed).\n\t\t// No special handling after first call - if file has been deleted, then it's game over.\n\n\t\t// Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n\t\t// If we waited too long, we will log error event and proceed with call.\n\t\t// It may result in failure for user, but refreshing document would address it.\n\t\t// Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n\t\t// to unblock the process.\n\t\tawait PerformanceEvent.timedExecAsync(\n\t\t\tthis.logger,\n\t\t\t{ eventName: \"JoinSessionSyncWait\" },\n\t\t\tasync (event) => {\n\t\t\t\tconst timeoutRes = 51; // anything will work here\n\t\t\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t\t\tconst timeoutP = new Promise<number>((resolve) => {\n\t\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\t\tresolve(timeoutRes);\n\t\t\t\t\t}, 15000);\n\t\t\t\t});\n\t\t\t\tconst res = await Promise.race([\n\t\t\t\t\ttimeoutP,\n\t\t\t\t\t// cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n\t\t\t\t\tthis.treesLatestDeferral.promise.finally(() => clearTimeout(timer)),\n\t\t\t\t]);\n\t\t\t\tif (res === timeoutRes) {\n\t\t\t\t\tevent.cancel();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ start: true, end: true, cancel: \"generic\" },\n\t\t);\n\t\treturn super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n\t}\n}\n\n/**\n * @alpha\n */\nexport interface ICacheAndTracker {\n\tcache: IOdspCache;\n\tepochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n\tpersistedCacheArg: IPersistedCache,\n\tnonpersistentCache: INonPersistentCache,\n\tfileEntry: IFileEntry,\n\tlogger: ITelemetryLoggerExt,\n\tclientIsSummarizer?: boolean,\n): ICacheAndTracker {\n\tconst epochTracker = new EpochTrackerWithRedemption(\n\t\tpersistedCacheArg,\n\t\tfileEntry,\n\t\tlogger,\n\t\tclientIsSummarizer,\n\t);\n\treturn {\n\t\tcache: {\n\t\t\t...nonpersistentCache,\n\t\t\tpersistedCache: epochTracker,\n\t\t},\n\t\tepochTracker,\n\t};\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.0.5";
8
+ export declare const pkgVersion = "2.0.6";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/odsp-driver";
8
- export const pkgVersion = "2.0.5";
8
+ export const pkgVersion = "2.0.6";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,6BAA6B,CAAC;AACrD,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,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.0.5\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,6BAA6B,CAAC;AACrD,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,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.0.6\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/odsp-driver",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Socket storage implementation for SPO and ODC",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -77,15 +77,15 @@
77
77
  "temp-directory": "nyc/.nyc_output"
78
78
  },
79
79
  "dependencies": {
80
- "@fluid-internal/client-utils": "~2.0.5",
81
- "@fluidframework/core-interfaces": "~2.0.5",
82
- "@fluidframework/core-utils": "~2.0.5",
83
- "@fluidframework/driver-base": "~2.0.5",
84
- "@fluidframework/driver-definitions": "~2.0.5",
85
- "@fluidframework/driver-utils": "~2.0.5",
86
- "@fluidframework/odsp-doclib-utils": "~2.0.5",
87
- "@fluidframework/odsp-driver-definitions": "~2.0.5",
88
- "@fluidframework/telemetry-utils": "~2.0.5",
80
+ "@fluid-internal/client-utils": "~2.0.6",
81
+ "@fluidframework/core-interfaces": "~2.0.6",
82
+ "@fluidframework/core-utils": "~2.0.6",
83
+ "@fluidframework/driver-base": "~2.0.6",
84
+ "@fluidframework/driver-definitions": "~2.0.6",
85
+ "@fluidframework/driver-utils": "~2.0.6",
86
+ "@fluidframework/odsp-doclib-utils": "~2.0.6",
87
+ "@fluidframework/odsp-driver-definitions": "~2.0.6",
88
+ "@fluidframework/telemetry-utils": "~2.0.6",
89
89
  "node-fetch": "^2.6.9",
90
90
  "socket.io-client": "^4.7.3",
91
91
  "uuid": "^9.0.0"
@@ -93,7 +93,7 @@
93
93
  "devDependencies": {
94
94
  "@arethetypeswrong/cli": "^0.15.2",
95
95
  "@biomejs/biome": "^1.7.3",
96
- "@fluid-internal/mocha-test-setup": "~2.0.5",
96
+ "@fluid-internal/mocha-test-setup": "~2.0.6",
97
97
  "@fluid-tools/build-cli": "^0.39.0",
98
98
  "@fluidframework/build-common": "^2.0.3",
99
99
  "@fluidframework/build-tools": "^0.39.0",
@@ -21,6 +21,7 @@ import {
21
21
  OdspErrorTypes,
22
22
  maximumCacheDurationMs,
23
23
  snapshotKey,
24
+ snapshotWithLoadingGroupIdKey,
24
25
  } from "@fluidframework/odsp-driver-definitions/internal";
25
26
  import {
26
27
  ITelemetryLoggerExt,
@@ -146,7 +147,7 @@ export class EpochTracker implements IPersistedFileCache {
146
147
  }
147
148
  // Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately
148
149
  // expire all old caches that do not have cacheEntryTime
149
- if (entry.type === snapshotKey) {
150
+ if (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {
150
151
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
151
152
  const cacheTime = value.value?.cacheEntryTime;
152
153
  const currentTime = Date.now();
@@ -177,7 +178,7 @@ export class EpochTracker implements IPersistedFileCache {
177
178
  assert(this._fluidEpoch !== undefined, 0x1dd /* "no epoch" */);
178
179
  // For snapshots, the value should have the cacheEntryTime.
179
180
  // This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.
180
- if (entry.type === snapshotKey) {
181
+ if (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {
181
182
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
182
183
  value.cacheEntryTime = value.cacheEntryTime ?? Date.now();
183
184
  }
@@ -519,7 +520,7 @@ export class EpochTrackerWithRedemption extends EpochTracker {
519
520
  let result = super.get(entry);
520
521
 
521
522
  // equivalence of what happens in fetchAndParseAsJSON()
522
- if (entry.type === snapshotKey) {
523
+ if (entry.type === snapshotKey || entry.type === snapshotWithLoadingGroupIdKey) {
523
524
  result = result
524
525
  .then((value) => {
525
526
  // If there is nothing in cache, we need to wait for network call to complete (and do redemption)
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/odsp-driver";
9
- export const pkgVersion = "2.0.5";
9
+ export const pkgVersion = "2.0.6";