@fluidframework/odsp-driver 2.93.0 → 2.101.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/compactSnapshotParser.d.ts +2 -2
  3. package/dist/compactSnapshotParser.d.ts.map +1 -1
  4. package/dist/compactSnapshotParser.js.map +1 -1
  5. package/dist/epochTracker.d.ts +8 -4
  6. package/dist/epochTracker.d.ts.map +1 -1
  7. package/dist/epochTracker.js +12 -9
  8. package/dist/epochTracker.js.map +1 -1
  9. package/dist/fetchSnapshot.d.ts +9 -6
  10. package/dist/fetchSnapshot.d.ts.map +1 -1
  11. package/dist/fetchSnapshot.js +8 -3
  12. package/dist/fetchSnapshot.js.map +1 -1
  13. package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
  14. package/dist/odspDelayLoadedDeltaStream.js +1 -3
  15. package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
  16. package/dist/odspDeltaStorageService.d.ts.map +1 -1
  17. package/dist/odspDeltaStorageService.js +3 -1
  18. package/dist/odspDeltaStorageService.js.map +1 -1
  19. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  20. package/dist/odspDocumentStorageManager.js +1 -1
  21. package/dist/odspDocumentStorageManager.js.map +1 -1
  22. package/dist/packageVersion.d.ts +1 -1
  23. package/dist/packageVersion.d.ts.map +1 -1
  24. package/dist/packageVersion.js +1 -1
  25. package/dist/packageVersion.js.map +1 -1
  26. package/dist/prefetchLatestSnapshot.d.ts.map +1 -1
  27. package/dist/prefetchLatestSnapshot.js +2 -2
  28. package/dist/prefetchLatestSnapshot.js.map +1 -1
  29. package/dist/vroom.d.ts +1 -2
  30. package/dist/vroom.d.ts.map +1 -1
  31. package/dist/vroom.js +2 -6
  32. package/dist/vroom.js.map +1 -1
  33. package/lib/compactSnapshotParser.d.ts +2 -2
  34. package/lib/compactSnapshotParser.d.ts.map +1 -1
  35. package/lib/compactSnapshotParser.js.map +1 -1
  36. package/lib/epochTracker.d.ts +8 -4
  37. package/lib/epochTracker.d.ts.map +1 -1
  38. package/lib/epochTracker.js +13 -10
  39. package/lib/epochTracker.js.map +1 -1
  40. package/lib/fetchSnapshot.d.ts +9 -6
  41. package/lib/fetchSnapshot.d.ts.map +1 -1
  42. package/lib/fetchSnapshot.js +8 -3
  43. package/lib/fetchSnapshot.js.map +1 -1
  44. package/lib/odspDelayLoadedDeltaStream.d.ts.map +1 -1
  45. package/lib/odspDelayLoadedDeltaStream.js +1 -3
  46. package/lib/odspDelayLoadedDeltaStream.js.map +1 -1
  47. package/lib/odspDeltaStorageService.d.ts.map +1 -1
  48. package/lib/odspDeltaStorageService.js +3 -1
  49. package/lib/odspDeltaStorageService.js.map +1 -1
  50. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  51. package/lib/odspDocumentStorageManager.js +1 -1
  52. package/lib/odspDocumentStorageManager.js.map +1 -1
  53. package/lib/packageVersion.d.ts +1 -1
  54. package/lib/packageVersion.d.ts.map +1 -1
  55. package/lib/packageVersion.js +1 -1
  56. package/lib/packageVersion.js.map +1 -1
  57. package/lib/prefetchLatestSnapshot.d.ts.map +1 -1
  58. package/lib/prefetchLatestSnapshot.js +2 -2
  59. package/lib/prefetchLatestSnapshot.js.map +1 -1
  60. package/lib/vroom.d.ts +1 -2
  61. package/lib/vroom.d.ts.map +1 -1
  62. package/lib/vroom.js +2 -6
  63. package/lib/vroom.js.map +1 -1
  64. package/package.json +13 -13
  65. package/src/compactSnapshotParser.ts +2 -2
  66. package/src/epochTracker.ts +30 -11
  67. package/src/fetchSnapshot.ts +13 -7
  68. package/src/odspDelayLoadedDeltaStream.ts +0 -5
  69. package/src/odspDeltaStorageService.ts +12 -7
  70. package/src/odspDocumentStorageManager.ts +1 -0
  71. package/src/packageVersion.ts +1 -1
  72. package/src/prefetchLatestSnapshot.ts +2 -1
  73. package/src/vroom.ts +1 -6
@@ -25,14 +25,18 @@ import {
25
25
  snapshotKey,
26
26
  snapshotWithLoadingGroupIdKey,
27
27
  } from "@fluidframework/odsp-driver-definitions/internal";
28
+ import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
28
29
  import {
29
- type ITelemetryLoggerExt,
30
30
  PerformanceEvent,
31
+ extractTelemetryLoggerExt,
31
32
  isFluidError,
32
33
  loggerToMonitoringContext,
33
34
  normalizeError,
35
+ toITelemetryLoggerExt,
34
36
  wrapError,
35
37
  } from "@fluidframework/telemetry-utils/internal";
38
+ // eslint-disable-next-line import-x/no-internal-modules -- Needed to avoid specialized /internal ITelemetryLoggerExt
39
+ import type { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/legacy";
36
40
  import { v4 as uuid } from "uuid";
37
41
 
38
42
  import { type IVersionedValueWithEpoch, persistedCacheValueVersion } from "./contracts.js";
@@ -90,6 +94,9 @@ export const Odsp409Error = "Odsp409Error";
90
94
  * then it also clears all the cached entries for the given container.
91
95
  * @legacy
92
96
  * @beta
97
+ *
98
+ * @privateRemarks
99
+ * This class should be hidden and an interface exposed to better manage internal types like telemetry logger.
93
100
  */
94
101
  export class EpochTracker implements IPersistedFileCache {
95
102
  private _fluidEpoch: string | undefined;
@@ -99,12 +106,15 @@ export class EpochTracker implements IPersistedFileCache {
99
106
  private readonly driverId = uuid();
100
107
  // This tracks the request number made by the driver instance.
101
108
  private networkCallNumber = 1;
109
+ private readonly loggerInternal: TelemetryLoggerExt;
102
110
  constructor(
103
111
  protected readonly cache: IPersistedCache,
104
112
  protected readonly fileEntry: IFileEntry,
105
113
  protected readonly logger: ITelemetryLoggerExt,
106
114
  protected readonly clientIsSummarizer?: boolean,
107
115
  ) {
116
+ this.loggerInternal = extractTelemetryLoggerExt(logger);
117
+
108
118
  // Limits the max number of concurrent requests to 24.
109
119
  this.rateLimiter = new RateLimiter(24);
110
120
 
@@ -121,7 +131,7 @@ export class EpochTracker implements IPersistedFileCache {
121
131
  assert(this._fluidEpoch === undefined, 0x1db /* "epoch exists" */);
122
132
  this._fluidEpoch = epoch;
123
133
 
124
- this.logger.sendTelemetryEvent({
134
+ this.loggerInternal.sendTelemetryEvent({
125
135
  eventName: "EpochLearnedFirstTime",
126
136
  epoch,
127
137
  fetchType,
@@ -137,7 +147,7 @@ export class EpochTracker implements IPersistedFileCache {
137
147
  const value = (await this.cache.get(
138
148
  this.fileEntryFromEntry(entry),
139
149
  )) as IVersionedValueWithEpoch;
140
- // Version mismatch between what the runtime expects and what it recieved.
150
+ // Version mismatch between what the runtime expects and what it received.
141
151
  // The cached value should not be used
142
152
  // eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior
143
153
  if (value === undefined || value.version !== persistedCacheValueVersion) {
@@ -161,7 +171,7 @@ export class EpochTracker implements IPersistedFileCache {
161
171
  cacheTime === undefined ||
162
172
  currentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs
163
173
  ) {
164
- this.logger.sendTelemetryEvent({
174
+ this.loggerInternal.sendTelemetryEvent({
165
175
  eventName: "odspVersionsCacheExpired",
166
176
  duration: currentTime - cacheTime,
167
177
  maxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,
@@ -172,7 +182,10 @@ export class EpochTracker implements IPersistedFileCache {
172
182
  }
173
183
  return value.value;
174
184
  } catch (error) {
175
- this.logger.sendErrorEvent({ eventName: "cacheFetchError", type: entry.type }, error);
185
+ this.loggerInternal.sendErrorEvent(
186
+ { eventName: "cacheFetchError", type: entry.type },
187
+ error,
188
+ );
176
189
  return undefined;
177
190
  }
178
191
  }
@@ -194,7 +207,10 @@ export class EpochTracker implements IPersistedFileCache {
194
207
  fluidEpoch: this._fluidEpoch,
195
208
  };
196
209
  return this.cache.put(this.fileEntryFromEntry(entry), data).catch((error) => {
197
- this.logger.sendErrorEvent({ eventName: "cachePutError", type: entry.type }, error);
210
+ this.loggerInternal.sendErrorEvent(
211
+ { eventName: "cachePutError", type: entry.type },
212
+ error,
213
+ );
198
214
  throw error;
199
215
  });
200
216
  }
@@ -203,7 +219,7 @@ export class EpochTracker implements IPersistedFileCache {
203
219
  try {
204
220
  return await this.cache.removeEntries(this.fileEntry);
205
221
  } catch (error) {
206
- this.logger.sendErrorEvent({ eventName: "removeCacheEntries" }, error);
222
+ this.loggerInternal.sendErrorEvent({ eventName: "removeCacheEntries" }, error);
207
223
  }
208
224
  }
209
225
 
@@ -456,7 +472,10 @@ export class EpochTracker implements IPersistedFileCache {
456
472
  fromCache,
457
473
  fetchType,
458
474
  });
459
- this.logger.sendErrorEvent({ eventName: "fileOverwrittenInStorage" }, epochError);
475
+ this.loggerInternal.sendErrorEvent(
476
+ { eventName: "fileOverwrittenInStorage" },
477
+ epochError,
478
+ );
460
479
  // If the epoch mismatches, then clear all entries for such file entry from cache.
461
480
  await this.removeEntries();
462
481
  throw epochError;
@@ -502,10 +521,10 @@ export class EpochTrackerWithRedemption extends EpochTracker {
502
521
  constructor(
503
522
  protected readonly cache: IPersistedCache,
504
523
  protected readonly fileEntry: IFileEntry,
505
- protected readonly logger: ITelemetryLoggerExt,
524
+ logger: TelemetryLoggerExt,
506
525
  protected readonly clientIsSummarizer?: boolean,
507
526
  ) {
508
- super(cache, fileEntry, logger, clientIsSummarizer);
527
+ super(cache, fileEntry, toITelemetryLoggerExt(logger), clientIsSummarizer);
509
528
  // Handles the rejected promise within treesLatestDeferral.
510
529
  this.treesLatestDeferral.promise.catch(() => {});
511
530
  }
@@ -635,7 +654,7 @@ export function createOdspCacheAndTracker(
635
654
  persistedCacheArg: IPersistedCache,
636
655
  nonpersistentCache: INonPersistentCache,
637
656
  fileEntry: IFileEntry,
638
- logger: ITelemetryLoggerExt,
657
+ logger: TelemetryLoggerExt,
639
658
  clientIsSummarizer?: boolean,
640
659
  ): ICacheAndTracker {
641
660
  const epochTracker = new EpochTrackerWithRedemption(
@@ -28,8 +28,8 @@ import {
28
28
  type InstrumentedStorageTokenFetcher,
29
29
  OdspErrorTypes,
30
30
  } from "@fluidframework/odsp-driver-definitions/internal";
31
+ import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
31
32
  import {
32
- type ITelemetryLoggerExt,
33
33
  PerformanceEvent,
34
34
  isFluidError,
35
35
  wrapError,
@@ -94,7 +94,7 @@ export async function fetchSnapshot(
94
94
  versionId: string,
95
95
  fetchFullSnapshot: boolean,
96
96
  forceAccessTokenViaAuthorizationHeader: boolean,
97
- logger: ITelemetryLoggerExt,
97
+ logger: TelemetryLoggerExt,
98
98
  snapshotDownloader: (url: string) => Promise<IOdspResponse<unknown>>,
99
99
  ): Promise<ISnapshot> {
100
100
  const path = `/trees/${versionId}`;
@@ -121,7 +121,7 @@ export async function fetchSnapshotWithRedeem(
121
121
  storageTokenFetcher: InstrumentedStorageTokenFetcher,
122
122
  snapshotOptions: ISnapshotOptions | undefined,
123
123
  forceAccessTokenViaAuthorizationHeader: boolean,
124
- logger: ITelemetryLoggerExt,
124
+ logger: TelemetryLoggerExt,
125
125
  snapshotDownloader: (
126
126
  finalOdspResolvedUrl: IOdspResolvedUrl,
127
127
  getAuthHeader: InstrumentedStorageTokenFetcher,
@@ -239,7 +239,7 @@ export async function fetchSnapshotWithRedeem(
239
239
  async function redeemSharingLink(
240
240
  odspResolvedUrl: IOdspResolvedUrl,
241
241
  getAuthHeader: InstrumentedStorageTokenFetcher,
242
- logger: ITelemetryLoggerExt,
242
+ logger: TelemetryLoggerExt,
243
243
  ): Promise<void> {
244
244
  await PerformanceEvent.timedExecAsync(
245
245
  logger,
@@ -306,7 +306,7 @@ async function fetchLatestSnapshotCore(
306
306
  odspResolvedUrl: IOdspResolvedUrl,
307
307
  getAuthHeader: InstrumentedStorageTokenFetcher,
308
308
  snapshotOptions: ISnapshotOptions | undefined,
309
- logger: ITelemetryLoggerExt,
309
+ logger: TelemetryLoggerExt,
310
310
  snapshotDownloader: (
311
311
  finalOdspResolvedUrl: IOdspResolvedUrl,
312
312
  getAuthHeader: InstrumentedStorageTokenFetcher,
@@ -713,15 +713,18 @@ function getTreeStatsCore(snapshotTree: ISnapshotTree, stats: ITreeStats): void
713
713
  /**
714
714
  * This function fetches the snapshot and parse it according to what is mentioned in response headers.
715
715
  * @param odspResolvedUrl - resolved odsp url.
716
- * @param storageToken - token to do the auth for network request.
717
- * @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
716
+ * @param getAuthHeader - function to fetch the auth header for the network request.
717
+ * @param tokenFetchOptions - options for fetching the token.
718
718
  * @param loadingGroupIds - loadingGroupIds for which snapshot needs to be downloaded. Note:
719
719
  * 1.) If undefined, then legacy trees latest call will be used where no groupId query param would be specified.
720
720
  * 2.) If [] is passed, then snapshot with all ungrouped data will be fetched.
721
721
  * 3.) If any groupId is specified like ["g1"], then snapshot for g1 group will be fetched.
722
+ * @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
723
+ * @param logger - logger for sending telemetry events.
722
724
  * @param snapshotFormatFetchType - Snapshot format to fetch.
723
725
  * @param controller - abort controller if caller needs to abort the network call.
724
726
  * @param epochTracker - epoch tracker used to add/validate epoch in the network call.
727
+ * @param scenarioName - scenario name for telemetry.
725
728
  * @returns fetched snapshot.
726
729
  */
727
730
  export const downloadSnapshot = mockify(
@@ -731,6 +734,7 @@ export const downloadSnapshot = mockify(
731
734
  tokenFetchOptions: TokenFetchOptionsEx,
732
735
  loadingGroupIds: string[] | undefined,
733
736
  snapshotOptions: ISnapshotOptions | undefined,
737
+ logger?: TelemetryLoggerExt,
734
738
  snapshotFormatFetchType?: SnapshotFormatSupportType,
735
739
  controller?: AbortController,
736
740
  epochTracker?: EpochTracker,
@@ -787,6 +791,7 @@ export const downloadSnapshot = mockify(
787
791
  "downloadSnapshot",
788
792
  );
789
793
  assert(authHeader !== null, 0x1e5 /* "Storage token should not be null" */);
794
+ logger?.sendTelemetryEvent({ eventName: "SnapshotAuthHeaderObtained" });
790
795
  const { body, headers } = getFormBodyAndHeaders(odspResolvedUrl, authHeader, header);
791
796
  const fetchOptions = {
792
797
  body,
@@ -813,6 +818,7 @@ export const downloadSnapshot = mockify(
813
818
  true,
814
819
  scenarioName,
815
820
  ) ?? fetchHelper(url, fetchOptions));
821
+ logger?.sendTelemetryEvent({ eventName: "SnapshotFetchResponseReceived" });
816
822
 
817
823
  return {
818
824
  odspResponse,
@@ -416,10 +416,6 @@ export class OdspDelayLoadedDeltaStream {
416
416
  const disableJoinSessionRefresh = this.mc.config.getBoolean(
417
417
  "Fluid.Driver.Odsp.disableJoinSessionRefresh",
418
418
  );
419
- // Previous gate "Fluid.Driver.Odsp.setSensitivityLabelHeader" was removed because it was sensitive to a timestamp-related bug that was fixed by PR #26318; using this new gate ensures that the bug fix is present.
420
- const setSensitivityLabelHeader = this.mc.config.getBoolean(
421
- "Fluid.Driver.Odsp.setSensitivityLabelHeaderPostFix",
422
- );
423
419
  const executeFetch = async (): Promise<{
424
420
  entryTime: number;
425
421
  joinSessionResponse: ISocketStorageDiscovery;
@@ -434,7 +430,6 @@ export class OdspDelayLoadedDeltaStream {
434
430
  requestSocketToken,
435
431
  options,
436
432
  disableJoinSessionRefresh,
437
- setSensitivityLabelHeader,
438
433
  isRefreshingJoinSession,
439
434
  displayName,
440
435
  );
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
7
+ import { LogLevel } from "@fluidframework/core-interfaces";
7
8
  import { assert } from "@fluidframework/core-utils/internal";
8
9
  import { validateMessages } from "@fluidframework/driver-base/internal";
9
10
  import type {
@@ -246,13 +247,17 @@ export class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {
246
247
 
247
248
  return streamObserver(stream, (result) => {
248
249
  if (result.done && opsFromSnapshot + opsFromCache + opsFromStorage !== 0) {
249
- this.logger.sendPerformanceEvent({
250
- eventName: "CacheOpsRetrieved",
251
- opsFromSnapshot,
252
- opsFromCache,
253
- opsFromStorage,
254
- reason: fetchReason,
255
- });
250
+ this.logger.sendPerformanceEvent(
251
+ {
252
+ eventName: "CacheOpsRetrieved",
253
+ opsFromSnapshot,
254
+ opsFromCache,
255
+ opsFromStorage,
256
+ reason: fetchReason,
257
+ },
258
+ undefined, // error
259
+ LogLevel.info,
260
+ );
256
261
  }
257
262
  });
258
263
  }
@@ -639,6 +639,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
639
639
  tokenFetchOptions,
640
640
  loadingGroupId,
641
641
  options,
642
+ this.logger,
642
643
  this.snapshotFormatFetchType,
643
644
  controller,
644
645
  this.epochTracker,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/odsp-driver";
9
- export const pkgVersion = "2.93.0";
9
+ export const pkgVersion = "2.101.0";
@@ -110,6 +110,7 @@ export async function prefetchLatestSnapshot(
110
110
  tokenFetchOptions,
111
111
  loadingGroupId,
112
112
  snapshotOptions,
113
+ odspLogger,
113
114
  undefined,
114
115
  controller,
115
116
  );
@@ -174,7 +175,7 @@ export async function prefetchLatestSnapshot(
174
175
  }, 5000);
175
176
  })
176
177
  .catch((error) => {
177
- // Remove it from the non persistent cache if an error occured.
178
+ // Remove it from the non persistent cache if an error occurred.
178
179
  snapshotNonPersistentCache?.remove(nonPersistentCacheKey);
179
180
  snapshotContentsWithEpochP.reject(error);
180
181
  throw error;
package/src/vroom.ts CHANGED
@@ -38,7 +38,6 @@ interface IJoinSessionBody {
38
38
  * which is used when establishing websocket connection with collab session backend service.
39
39
  * @param options - Options to fetch the token.
40
40
  * @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
41
- * @param setSensitivityLabelHeader - Whether the caller wants to set the Return-Sensitivity-Labels Prefer header in the join session request.
42
41
  * @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
43
42
  * @param displayName - display name used to identify client joining a session.
44
43
  * This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).
@@ -55,7 +54,6 @@ export const fetchJoinSession = mockify(
55
54
  requestSocketToken: boolean,
56
55
  options: TokenFetchOptionsEx,
57
56
  disableJoinSessionRefresh: boolean | undefined,
58
- setSensitivityLabelHeader: boolean | undefined,
59
57
  isRefreshingJoinSession: boolean,
60
58
  displayName: string | undefined,
61
59
  ): Promise<ISocketStorageDiscovery> => {
@@ -74,7 +72,6 @@ export const fetchJoinSession = mockify(
74
72
  requestSocketToken,
75
73
  ...tokenRefreshProps,
76
74
  refreshingSession: isRefreshingJoinSession,
77
- setSensitivityLabelHeader: setSensitivityLabelHeader ?? false,
78
75
  };
79
76
 
80
77
  return PerformanceEvent.timedExecAsync(
@@ -94,9 +91,7 @@ export const fetchJoinSession = mockify(
94
91
  if (!disableJoinSessionRefresh) {
95
92
  postBody += `Prefer: FluidRemoveCheckAccess\r\n`;
96
93
  }
97
- if (setSensitivityLabelHeader) {
98
- postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
99
- }
94
+ postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
100
95
  postBody += `_post: 1\r\n`;
101
96
 
102
97
  let requestBody: IJoinSessionBody | undefined;