@fluidframework/odsp-driver 2.0.0-dev-rc.1.0.0.228517 → 2.0.0-dev-rc.1.0.0.232845

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 (225) hide show
  1. package/api-report/odsp-driver.api.md +5 -5
  2. package/dist/compactSnapshotParser.d.ts +2 -2
  3. package/dist/compactSnapshotParser.d.ts.map +1 -1
  4. package/dist/compactSnapshotParser.js +8 -7
  5. package/dist/compactSnapshotParser.js.map +1 -1
  6. package/dist/compactSnapshotWriter.d.ts +2 -2
  7. package/dist/compactSnapshotWriter.d.ts.map +1 -1
  8. package/dist/compactSnapshotWriter.js +1 -1
  9. package/dist/compactSnapshotWriter.js.map +1 -1
  10. package/dist/contracts.d.ts +14 -0
  11. package/dist/contracts.d.ts.map +1 -1
  12. package/dist/contracts.js +5 -1
  13. package/dist/contracts.js.map +1 -1
  14. package/dist/createFile.d.ts +1 -1
  15. package/dist/createFile.d.ts.map +1 -1
  16. package/dist/createFile.js +9 -28
  17. package/dist/createFile.js.map +1 -1
  18. package/dist/createNewContainerOnExistingFile.d.ts.map +1 -1
  19. package/dist/createNewContainerOnExistingFile.js.map +1 -1
  20. package/dist/createNewUtils.d.ts +2 -2
  21. package/dist/createNewUtils.d.ts.map +1 -1
  22. package/dist/createNewUtils.js +4 -3
  23. package/dist/createNewUtils.js.map +1 -1
  24. package/dist/createOdspCreateContainerRequest.d.ts +2 -2
  25. package/dist/createOdspCreateContainerRequest.d.ts.map +1 -1
  26. package/dist/createOdspCreateContainerRequest.js.map +1 -1
  27. package/dist/epochTracker.d.ts.map +1 -1
  28. package/dist/epochTracker.js +3 -4
  29. package/dist/epochTracker.js.map +1 -1
  30. package/dist/fetchSnapshot.d.ts +4 -4
  31. package/dist/fetchSnapshot.d.ts.map +1 -1
  32. package/dist/fetchSnapshot.js +12 -13
  33. package/dist/fetchSnapshot.js.map +1 -1
  34. package/dist/getFileLink.d.ts.map +1 -1
  35. package/dist/getFileLink.js +3 -3
  36. package/dist/getFileLink.js.map +1 -1
  37. package/dist/localOdspDriver/localOdspDocumentService.d.ts +3 -2
  38. package/dist/localOdspDriver/localOdspDocumentService.d.ts.map +1 -1
  39. package/dist/localOdspDriver/localOdspDocumentService.js +3 -1
  40. package/dist/localOdspDriver/localOdspDocumentService.js.map +1 -1
  41. package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts +2 -1
  42. package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
  43. package/dist/localOdspDriver/localOdspDocumentStorageManager.js +3 -0
  44. package/dist/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
  45. package/dist/odsp-driver-alpha.d.ts +4 -3
  46. package/dist/odsp-driver-beta.d.ts +3 -3
  47. package/dist/odsp-driver-public.d.ts +3 -3
  48. package/dist/odsp-driver-untrimmed.d.ts +5 -4
  49. package/dist/odspCache.d.ts +2 -2
  50. package/dist/odspCache.d.ts.map +1 -1
  51. package/dist/odspCache.js.map +1 -1
  52. package/dist/odspDelayLoadedDeltaStream.d.ts +5 -1
  53. package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
  54. package/dist/odspDelayLoadedDeltaStream.js +56 -5
  55. package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
  56. package/dist/odspDocumentService.d.ts +3 -2
  57. package/dist/odspDocumentService.d.ts.map +1 -1
  58. package/dist/odspDocumentService.js +6 -3
  59. package/dist/odspDocumentService.js.map +1 -1
  60. package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  61. package/dist/odspDocumentServiceFactoryCore.js +1 -8
  62. package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
  63. package/dist/odspDocumentStorageManager.d.ts +2 -1
  64. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  65. package/dist/odspDocumentStorageManager.js +30 -11
  66. package/dist/odspDocumentStorageManager.js.map +1 -1
  67. package/dist/odspDocumentStorageServiceBase.d.ts +3 -3
  68. package/dist/odspDocumentStorageServiceBase.d.ts.map +1 -1
  69. package/dist/odspDocumentStorageServiceBase.js +3 -3
  70. package/dist/odspDocumentStorageServiceBase.js.map +1 -1
  71. package/dist/odspDriverUrlResolver.d.ts.map +1 -1
  72. package/dist/odspDriverUrlResolver.js +2 -11
  73. package/dist/odspDriverUrlResolver.js.map +1 -1
  74. package/dist/odspError.d.ts.map +1 -1
  75. package/dist/odspError.js +2 -2
  76. package/dist/odspError.js.map +1 -1
  77. package/dist/odspPublicUtils.d.ts +1 -0
  78. package/dist/odspPublicUtils.d.ts.map +1 -1
  79. package/dist/odspPublicUtils.js.map +1 -1
  80. package/dist/odspSnapshotParser.d.ts +2 -2
  81. package/dist/odspSnapshotParser.d.ts.map +1 -1
  82. package/dist/odspSnapshotParser.js +2 -1
  83. package/dist/odspSnapshotParser.js.map +1 -1
  84. package/dist/odspUtils.d.ts +11 -7
  85. package/dist/odspUtils.d.ts.map +1 -1
  86. package/dist/odspUtils.js +20 -16
  87. package/dist/odspUtils.js.map +1 -1
  88. package/dist/packageVersion.d.ts +1 -1
  89. package/dist/packageVersion.js +1 -1
  90. package/dist/packageVersion.js.map +1 -1
  91. package/dist/retryErrorsStorageAdapter.d.ts +2 -1
  92. package/dist/retryErrorsStorageAdapter.d.ts.map +1 -1
  93. package/dist/retryErrorsStorageAdapter.js +8 -0
  94. package/dist/retryErrorsStorageAdapter.js.map +1 -1
  95. package/dist/retryUtils.js +1 -1
  96. package/dist/retryUtils.js.map +1 -1
  97. package/dist/tsdoc-metadata.json +1 -1
  98. package/dist/zipItDataRepresentationUtils.js +2 -2
  99. package/dist/zipItDataRepresentationUtils.js.map +1 -1
  100. package/lib/compactSnapshotParser.d.mts +2 -2
  101. package/lib/compactSnapshotParser.d.mts.map +1 -1
  102. package/lib/compactSnapshotParser.mjs +8 -7
  103. package/lib/compactSnapshotParser.mjs.map +1 -1
  104. package/lib/compactSnapshotWriter.d.mts +2 -2
  105. package/lib/compactSnapshotWriter.d.mts.map +1 -1
  106. package/lib/compactSnapshotWriter.mjs +1 -1
  107. package/lib/compactSnapshotWriter.mjs.map +1 -1
  108. package/lib/contracts.d.mts +14 -0
  109. package/lib/contracts.d.mts.map +1 -1
  110. package/lib/contracts.mjs +4 -0
  111. package/lib/contracts.mjs.map +1 -1
  112. package/lib/createFile.d.mts +1 -1
  113. package/lib/createFile.d.mts.map +1 -1
  114. package/lib/createFile.mjs +10 -29
  115. package/lib/createFile.mjs.map +1 -1
  116. package/lib/createNewContainerOnExistingFile.d.mts.map +1 -1
  117. package/lib/createNewContainerOnExistingFile.mjs.map +1 -1
  118. package/lib/createNewUtils.d.mts +2 -2
  119. package/lib/createNewUtils.d.mts.map +1 -1
  120. package/lib/createNewUtils.mjs +4 -3
  121. package/lib/createNewUtils.mjs.map +1 -1
  122. package/lib/createOdspCreateContainerRequest.d.mts +2 -2
  123. package/lib/createOdspCreateContainerRequest.d.mts.map +1 -1
  124. package/lib/createOdspCreateContainerRequest.mjs.map +1 -1
  125. package/lib/epochTracker.d.mts.map +1 -1
  126. package/lib/epochTracker.mjs +4 -5
  127. package/lib/epochTracker.mjs.map +1 -1
  128. package/lib/fetchSnapshot.d.mts +4 -4
  129. package/lib/fetchSnapshot.d.mts.map +1 -1
  130. package/lib/fetchSnapshot.mjs +13 -14
  131. package/lib/fetchSnapshot.mjs.map +1 -1
  132. package/lib/getFileLink.d.mts.map +1 -1
  133. package/lib/getFileLink.mjs +3 -3
  134. package/lib/getFileLink.mjs.map +1 -1
  135. package/lib/localOdspDriver/localOdspDocumentService.d.mts +3 -2
  136. package/lib/localOdspDriver/localOdspDocumentService.d.mts.map +1 -1
  137. package/lib/localOdspDriver/localOdspDocumentService.mjs +3 -1
  138. package/lib/localOdspDriver/localOdspDocumentService.mjs.map +1 -1
  139. package/lib/localOdspDriver/localOdspDocumentStorageManager.d.mts +2 -1
  140. package/lib/localOdspDriver/localOdspDocumentStorageManager.d.mts.map +1 -1
  141. package/lib/localOdspDriver/localOdspDocumentStorageManager.mjs +3 -0
  142. package/lib/localOdspDriver/localOdspDocumentStorageManager.mjs.map +1 -1
  143. package/lib/odsp-driver-alpha.d.mts +4 -3
  144. package/lib/odsp-driver-beta.d.mts +3 -3
  145. package/lib/odsp-driver-public.d.mts +3 -3
  146. package/lib/odsp-driver-untrimmed.d.mts +5 -4
  147. package/lib/odspCache.d.mts +2 -2
  148. package/lib/odspCache.d.mts.map +1 -1
  149. package/lib/odspCache.mjs.map +1 -1
  150. package/lib/odspDelayLoadedDeltaStream.d.mts +5 -1
  151. package/lib/odspDelayLoadedDeltaStream.d.mts.map +1 -1
  152. package/lib/odspDelayLoadedDeltaStream.mjs +57 -6
  153. package/lib/odspDelayLoadedDeltaStream.mjs.map +1 -1
  154. package/lib/odspDocumentService.d.mts +3 -2
  155. package/lib/odspDocumentService.d.mts.map +1 -1
  156. package/lib/odspDocumentService.mjs +6 -3
  157. package/lib/odspDocumentService.mjs.map +1 -1
  158. package/lib/odspDocumentServiceFactoryCore.d.mts.map +1 -1
  159. package/lib/odspDocumentServiceFactoryCore.mjs +2 -9
  160. package/lib/odspDocumentServiceFactoryCore.mjs.map +1 -1
  161. package/lib/odspDocumentStorageManager.d.mts +2 -1
  162. package/lib/odspDocumentStorageManager.d.mts.map +1 -1
  163. package/lib/odspDocumentStorageManager.mjs +33 -14
  164. package/lib/odspDocumentStorageManager.mjs.map +1 -1
  165. package/lib/odspDocumentStorageServiceBase.d.mts +3 -3
  166. package/lib/odspDocumentStorageServiceBase.d.mts.map +1 -1
  167. package/lib/odspDocumentStorageServiceBase.mjs +3 -3
  168. package/lib/odspDocumentStorageServiceBase.mjs.map +1 -1
  169. package/lib/odspDriverUrlResolver.d.mts.map +1 -1
  170. package/lib/odspDriverUrlResolver.mjs +4 -13
  171. package/lib/odspDriverUrlResolver.mjs.map +1 -1
  172. package/lib/odspError.d.mts.map +1 -1
  173. package/lib/odspError.mjs +2 -2
  174. package/lib/odspError.mjs.map +1 -1
  175. package/lib/odspPublicUtils.d.mts +1 -0
  176. package/lib/odspPublicUtils.d.mts.map +1 -1
  177. package/lib/odspPublicUtils.mjs.map +1 -1
  178. package/lib/odspSnapshotParser.d.mts +2 -2
  179. package/lib/odspSnapshotParser.d.mts.map +1 -1
  180. package/lib/odspSnapshotParser.mjs +2 -1
  181. package/lib/odspSnapshotParser.mjs.map +1 -1
  182. package/lib/odspUtils.d.mts +11 -7
  183. package/lib/odspUtils.d.mts.map +1 -1
  184. package/lib/odspUtils.mjs +19 -16
  185. package/lib/odspUtils.mjs.map +1 -1
  186. package/lib/packageVersion.d.mts +1 -1
  187. package/lib/packageVersion.mjs +1 -1
  188. package/lib/packageVersion.mjs.map +1 -1
  189. package/lib/retryErrorsStorageAdapter.d.mts +2 -1
  190. package/lib/retryErrorsStorageAdapter.d.mts.map +1 -1
  191. package/lib/retryErrorsStorageAdapter.mjs +9 -1
  192. package/lib/retryErrorsStorageAdapter.mjs.map +1 -1
  193. package/lib/retryUtils.mjs +2 -2
  194. package/lib/retryUtils.mjs.map +1 -1
  195. package/lib/zipItDataRepresentationUtils.mjs +2 -2
  196. package/lib/zipItDataRepresentationUtils.mjs.map +1 -1
  197. package/package.json +25 -16
  198. package/src/compactSnapshotParser.ts +10 -9
  199. package/src/compactSnapshotWriter.ts +3 -3
  200. package/src/contracts.ts +17 -0
  201. package/src/createFile.ts +10 -38
  202. package/src/createNewContainerOnExistingFile.ts +2 -2
  203. package/src/createNewUtils.ts +7 -6
  204. package/src/createOdspCreateContainerRequest.ts +2 -2
  205. package/src/epochTracker.ts +4 -4
  206. package/src/fetchSnapshot.ts +21 -22
  207. package/src/getFileLink.ts +3 -3
  208. package/src/localOdspDriver/localOdspDocumentService.ts +9 -2
  209. package/src/localOdspDriver/localOdspDocumentStorageManager.ts +10 -3
  210. package/src/odspCache.ts +2 -2
  211. package/src/odspDelayLoadedDeltaStream.ts +67 -6
  212. package/src/odspDocumentService.ts +10 -2
  213. package/src/odspDocumentServiceFactoryCore.ts +3 -11
  214. package/src/odspDocumentStorageManager.ts +60 -27
  215. package/src/odspDocumentStorageServiceBase.ts +8 -5
  216. package/src/odspDriverUrlResolver.ts +3 -17
  217. package/src/odspError.ts +2 -3
  218. package/src/odspPublicUtils.ts +1 -0
  219. package/src/odspSnapshotParser.ts +5 -6
  220. package/src/odspUtils.ts +34 -28
  221. package/src/packageVersion.ts +1 -1
  222. package/src/retryErrorsStorageAdapter.ts +12 -1
  223. package/src/retryUtils.ts +2 -2
  224. package/src/zipItDataRepresentationUtils.ts +2 -2
  225. /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { performance } from "@fluid-internal/client-utils";
7
+ import { ISignalEnvelope } from "@fluidframework/core-interfaces";
7
8
  import { assert } from "@fluidframework/core-utils";
8
9
  import {
9
10
  IFluidErrorBase,
@@ -14,20 +15,23 @@ import {
14
15
  IDocumentDeltaConnection,
15
16
  IResolvedUrl,
16
17
  IDocumentServicePolicies,
17
- DriverErrorType,
18
18
  } from "@fluidframework/driver-definitions";
19
19
  import {
20
20
  DeltaStreamConnectionForbiddenError,
21
21
  NonRetryableError,
22
22
  } from "@fluidframework/driver-utils";
23
- import { IClient, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
23
+ import {
24
+ IClient,
25
+ ISequencedDocumentMessage,
26
+ ISignalMessage,
27
+ } from "@fluidframework/protocol-definitions";
24
28
  import {
25
29
  IOdspResolvedUrl,
26
30
  TokenFetchOptions,
27
31
  HostStoragePolicy,
28
32
  InstrumentedStorageTokenFetcher,
29
33
  ISocketStorageDiscovery,
30
- OdspErrorType,
34
+ OdspErrorTypes,
31
35
  } from "@fluidframework/odsp-driver-definitions";
32
36
  import { hasFacetCodes } from "@fluidframework/odsp-doclib-utils";
33
37
  import { IOdspCache } from "./odspCache";
@@ -40,6 +44,7 @@ import {
40
44
  import { fetchJoinSession } from "./vroom";
41
45
  import { EpochTracker } from "./epochTracker";
42
46
  import { pkgVersion as driverVersion } from "./packageVersion";
47
+ import { policyLabelsUpdatesSignalType } from "./contracts";
43
48
 
44
49
  /**
45
50
  * This OdspDelayLoadedDeltaStream is used by OdspDocumentService.ts to delay load the delta connection
@@ -55,6 +60,12 @@ export class OdspDelayLoadedDeltaStream {
55
60
 
56
61
  private _relayServiceTenantAndSessionId: string | undefined;
57
62
 
63
+ // Tracks the time at which the Policy Labels were updated the last time. This is used to resolve race conditions
64
+ // between label updates from the join session and the Fluid signals and they could have same or different timestamps.
65
+ // So this timestamp is updated with timestamp from the service/signals with the most recent timestamp. We could also
66
+ // receive stale data from join session as that call is made at intervals, so we need to update with only most recent data.
67
+ private labelUpdateTimestamp: number = -1;
68
+
58
69
  /**
59
70
  * @param odspResolvedUrl - resolved url identifying document that will be managed by this service instance.
60
71
  * @param policies - Document service policies.
@@ -82,6 +93,7 @@ export class OdspDelayLoadedDeltaStream {
82
93
  private readonly hostPolicy: HostStoragePolicy,
83
94
  private readonly epochTracker: EpochTracker,
84
95
  private readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,
96
+ private readonly metadataUpdateHandler: (metadata: Record<string, string>) => void,
85
97
  private readonly socketReferenceKeyPrefix?: string,
86
98
  ) {
87
99
  this.joinSessionKey = getJoinSessionCacheKey(this.odspResolvedUrl);
@@ -155,13 +167,18 @@ export class OdspDelayLoadedDeltaStream {
155
167
  throw this.annotateConnectionError(
156
168
  new NonRetryableError(
157
169
  "Websocket token is null",
158
- OdspErrorType.fetchTokenError,
170
+ OdspErrorTypes.fetchTokenError,
159
171
  { driverVersion },
160
172
  ),
161
173
  "getWebsocketToken",
162
174
  !requestWebsocketTokenFromJoinSession,
163
175
  );
164
176
  }
177
+ if (websocketEndpoint.sensitivityLabelsInfo !== undefined) {
178
+ this.emitMetaDataUpdateEvent({
179
+ sensitivityLabelsInfo: websocketEndpoint.sensitivityLabelsInfo,
180
+ });
181
+ }
165
182
  try {
166
183
  const connection = await this.createDeltaConnection(
167
184
  websocketEndpoint.tenantId,
@@ -173,6 +190,9 @@ export class OdspDelayLoadedDeltaStream {
173
190
  connection.on("op", (documentId, ops: ISequencedDocumentMessage[]) => {
174
191
  this.opsReceived(ops);
175
192
  });
193
+ connection.on("signal", this.signalHandler);
194
+ // Also process the initial signals
195
+ this.signalHandler(connection.initialSignals);
176
196
  // On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again
177
197
  // get the auth error on reconnecting and face latency.
178
198
  connection.once("disconnect", (error: any) => {
@@ -181,7 +201,7 @@ export class OdspDelayLoadedDeltaStream {
181
201
  if (
182
202
  typeof error === "object" &&
183
203
  error !== null &&
184
- error.errorType === DriverErrorType.authorizationError
204
+ error.errorType === OdspErrorTypes.authorizationError
185
205
  ) {
186
206
  this.cache.sessionJoinCache.remove(this.joinSessionKey);
187
207
  }
@@ -211,6 +231,26 @@ export class OdspDelayLoadedDeltaStream {
211
231
  });
212
232
  }
213
233
 
234
+ private readonly signalHandler = (signalsArg: ISignalMessage | ISignalMessage[]) => {
235
+ const signals = Array.isArray(signalsArg) ? signalsArg : [signalsArg];
236
+ signals.forEach((signal: ISignalMessage) => {
237
+ // Make sure it is not for a specific client as `PolicyLabelsUpdate` is meant for all clients.
238
+ if (signal.clientId === null) {
239
+ // We could have some issues/irregularities in parsing signals, so put it in try/catch block
240
+ // and ignore the error as we can have labels update later on through join session response.
241
+ let envelope: ISignalEnvelope | undefined;
242
+ try {
243
+ envelope = JSON.parse(signal.content as string) as ISignalEnvelope;
244
+ } catch (err) {}
245
+ if (envelope?.contents?.type === policyLabelsUpdatesSignalType) {
246
+ this.emitMetaDataUpdateEvent({
247
+ sensitivityLabelsInfo: JSON.stringify(envelope.contents.content),
248
+ });
249
+ }
250
+ }
251
+ });
252
+ };
253
+
214
254
  private clearJoinSessionTimer() {
215
255
  if (this.joinSessionRefreshTimer !== undefined) {
216
256
  clearTimeout(this.joinSessionRefreshTimer);
@@ -273,7 +313,7 @@ export class OdspDelayLoadedDeltaStream {
273
313
  this.clearJoinSessionTimer();
274
314
  throw new NonRetryableError(
275
315
  "JoinSessionRefreshTimerNotCancelled",
276
- DriverErrorType.genericError,
316
+ OdspErrorTypes.genericError,
277
317
  {
278
318
  driverVersion,
279
319
  details: JSON.stringify({
@@ -339,6 +379,12 @@ export class OdspDelayLoadedDeltaStream {
339
379
  isRefreshingJoinSession,
340
380
  this.hostPolicy.sessionOptions?.unauthenticatedUserDisplayName,
341
381
  );
382
+ // Emit event only in case it is fetched from the network.
383
+ if (joinSessionResponse.sensitivityLabelsInfo !== undefined) {
384
+ this.emitMetaDataUpdateEvent({
385
+ sensitivityLabelsInfo: joinSessionResponse.sensitivityLabelsInfo,
386
+ });
387
+ }
342
388
  return {
343
389
  entryTime: Date.now(),
344
390
  joinSessionResponse,
@@ -402,6 +448,21 @@ export class OdspDelayLoadedDeltaStream {
402
448
  return response.joinSessionResponse;
403
449
  }
404
450
 
451
+ private emitMetaDataUpdateEvent(metadata: Record<string, string>) {
452
+ const label = JSON.parse(metadata.sensitivityLabelsInfo) as {
453
+ labels: unknown;
454
+ timestamp: number;
455
+ };
456
+ const time = label.timestamp;
457
+ assert(time > 0, "time should be positive");
458
+ if (time > this.labelUpdateTimestamp) {
459
+ this.labelUpdateTimestamp = time;
460
+ this.metadataUpdateHandler({
461
+ sensitivityLabelsInfo: metadata.sensitivityLabelsInfo,
462
+ });
463
+ }
464
+ }
465
+
405
466
  private calculateJoinSessionRefreshDelta(
406
467
  responseFetchTime: number,
407
468
  refreshSessionDurationSeconds: number,
@@ -8,6 +8,7 @@ import {
8
8
  createChildMonitoringContext,
9
9
  MonitoringContext,
10
10
  } from "@fluidframework/telemetry-utils";
11
+ import { TypedEventEmitter } from "@fluid-internal/client-utils";
11
12
  import { assert } from "@fluidframework/core-utils";
12
13
  import {
13
14
  IDocumentDeltaConnection,
@@ -16,6 +17,7 @@ import {
16
17
  IResolvedUrl,
17
18
  IDocumentStorageService,
18
19
  IDocumentServicePolicies,
20
+ IDocumentServiceEvents,
19
21
  } from "@fluidframework/driver-definitions";
20
22
  import { IClient, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
21
23
  import {
@@ -40,7 +42,10 @@ import type { OdspDelayLoadedDeltaStream } from "./odspDelayLoadedDeltaStream";
40
42
  * The DocumentService manages the Socket.IO connection and manages routing requests to connected
41
43
  * clients
42
44
  */
43
- export class OdspDocumentService implements IDocumentService {
45
+ export class OdspDocumentService
46
+ extends TypedEventEmitter<IDocumentServiceEvents>
47
+ implements IDocumentService
48
+ {
44
49
  private readonly _policies: IDocumentServicePolicies;
45
50
 
46
51
  // Promise to load socket module only once.
@@ -123,6 +128,7 @@ export class OdspDocumentService implements IDocumentService {
123
128
  private readonly socketReferenceKeyPrefix?: string,
124
129
  private readonly clientIsSummarizer?: boolean,
125
130
  ) {
131
+ super();
126
132
  this._policies = {
127
133
  // load in storage-only mode if a file version is specified
128
134
  storageOnly: odspResolvedUrl.fileVersion !== undefined,
@@ -141,6 +147,7 @@ export class OdspDocumentService implements IDocumentService {
141
147
  });
142
148
 
143
149
  this.hostPolicy = hostPolicy;
150
+ this.hostPolicy.supportGetSnapshotApi = this._policies.supportGetSnapshotApi;
144
151
  if (this.clientIsSummarizer) {
145
152
  this.hostPolicy = { ...this.hostPolicy, summarizerClient: true };
146
153
  }
@@ -282,6 +289,7 @@ export class OdspDocumentService implements IDocumentService {
282
289
  this.hostPolicy,
283
290
  this.epochTracker,
284
291
  (ops: ISequencedDocumentMessage[]) => this.opsReceived(ops),
292
+ (metadata: Record<string, string>) => this.emit("metadataUpdate", metadata),
285
293
  this.socketReferenceKeyPrefix,
286
294
  );
287
295
  return this.odspDelayLoadedDeltaStream;
@@ -289,7 +297,7 @@ export class OdspDocumentService implements IDocumentService {
289
297
 
290
298
  public dispose(error?: any) {
291
299
  // Error might indicate mismatch between client & server knowledge about file
292
- // (DriverErrorType.fileOverwrittenInStorage).
300
+ // (OdspErrorTypes.fileOverwrittenInStorage).
293
301
  // For example, file might have been overwritten in storage without generating new epoch
294
302
  // In such case client cached info is stale and has to be removed.
295
303
  if (error !== undefined) {
@@ -26,7 +26,6 @@ import {
26
26
  IOdspUrlParts,
27
27
  SharingLinkScope,
28
28
  SharingLinkRole,
29
- ShareLinkTypes,
30
29
  ISharingLinkKind,
31
30
  ISocketStorageDiscovery,
32
31
  IRelaySessionAwareDriverFactory,
@@ -102,7 +101,7 @@ export class OdspDocumentServiceFactoryCore
102
101
  };
103
102
 
104
103
  let fileInfo: INewFileInfo | IExistingFileInfo;
105
- let createShareLinkParam: ShareLinkTypes | ISharingLinkKind | undefined;
104
+ let createShareLinkParam: ISharingLinkKind | undefined;
106
105
  if (odspResolvedUrl.itemId) {
107
106
  fileInfo = {
108
107
  type: "Existing",
@@ -161,7 +160,6 @@ export class OdspDocumentServiceFactoryCore
161
160
  createShareLinkParam: createShareLinkParam
162
161
  ? JSON.stringify(createShareLinkParam)
163
162
  : undefined,
164
- enableShareLinkWithCreate: this.hostPolicy.enableShareLinkWithCreate,
165
163
  enableSingleRequestForShareLinkWithCreate:
166
164
  this.hostPolicy.enableSingleRequestForShareLinkWithCreate,
167
165
  },
@@ -202,7 +200,6 @@ export class OdspDocumentServiceFactoryCore
202
200
  ?.forceAccessTokenViaAuthorizationHeader,
203
201
  odspResolvedUrl.isClpCompliantApp,
204
202
  this.hostPolicy.enableSingleRequestForShareLinkWithCreate,
205
- this.hostPolicy.enableShareLinkWithCreate,
206
203
  )
207
204
  : await module.createNewContainerOnExistingFile(
208
205
  getStorageToken,
@@ -330,9 +327,9 @@ export class OdspDocumentServiceFactoryCore
330
327
  function getSharingLinkParams(
331
328
  hostPolicy: HostStoragePolicy,
332
329
  searchParams: URLSearchParams,
333
- ): ShareLinkTypes | ISharingLinkKind | undefined {
330
+ ): ISharingLinkKind | undefined {
334
331
  // extract request parameters for creation of sharing link (if provided) if the feature is enabled
335
- let createShareLinkParam: ShareLinkTypes | ISharingLinkKind | undefined;
332
+ let createShareLinkParam: ISharingLinkKind | undefined;
336
333
  if (hostPolicy.enableSingleRequestForShareLinkWithCreate) {
337
334
  const createLinkScope = searchParams.get("createLinkScope");
338
335
  const createLinkRole = searchParams.get("createLinkRole");
@@ -344,11 +341,6 @@ function getSharingLinkParams(
344
341
  : {}),
345
342
  };
346
343
  }
347
- } else if (hostPolicy.enableShareLinkWithCreate) {
348
- const createLinkType = searchParams.get("createLinkType");
349
- if (createLinkType && ShareLinkTypes[createLinkType]) {
350
- createShareLinkParam = ShareLinkTypes[createLinkType || ""];
351
- }
352
344
  }
353
345
  return createShareLinkParam;
354
346
  }
@@ -16,12 +16,17 @@ import { assert, delay } from "@fluidframework/core-utils";
16
16
  import { LogLevel } from "@fluidframework/core-interfaces";
17
17
  import * as api from "@fluidframework/protocol-definitions";
18
18
  import { promiseRaceWithWinner } from "@fluidframework/driver-base";
19
- import { ISummaryContext, DriverErrorType, FetchSource } from "@fluidframework/driver-definitions";
19
+ import {
20
+ ISummaryContext,
21
+ FetchSource,
22
+ ISnapshot,
23
+ ISnapshotFetchOptions,
24
+ } from "@fluidframework/driver-definitions";
20
25
  import { RateLimiter, NonRetryableError } from "@fluidframework/driver-utils";
21
26
  import {
22
27
  IOdspResolvedUrl,
23
28
  ISnapshotOptions,
24
- OdspErrorType,
29
+ OdspErrorTypes,
25
30
  InstrumentedStorageTokenFetcher,
26
31
  getKeyForCacheEntry,
27
32
  } from "@fluidframework/odsp-driver-definitions";
@@ -30,6 +35,7 @@ import {
30
35
  HostStoragePolicyInternal,
31
36
  IVersionedValueWithEpoch,
32
37
  ISnapshotCachedEntry,
38
+ ISnapshotCachedEntry2,
33
39
  } from "./contracts";
34
40
  import {
35
41
  downloadSnapshot,
@@ -40,8 +46,11 @@ import {
40
46
  } from "./fetchSnapshot";
41
47
  import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth";
42
48
  import { IOdspCache, IPrefetchSnapshotContents } from "./odspCache";
43
- import { createCacheSnapshotKey, getWithRetryForTokenRefresh } from "./odspUtils";
44
- import { ISnapshotContents } from "./odspPublicUtils";
49
+ import {
50
+ createCacheSnapshotKey,
51
+ getWithRetryForTokenRefresh,
52
+ isInstanceOfISnapshot,
53
+ } from "./odspUtils";
45
54
  import { EpochTracker } from "./epochTracker";
46
55
  import type { OdspSummaryUploadManager } from "./odspSummaryUploadManager";
47
56
  import { FlushResult } from "./odspDocumentDeltaConnection";
@@ -204,6 +213,15 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
204
213
  return super.getSnapshotTree(version, scenarioName);
205
214
  }
206
215
 
216
+ public async getSnapshot(snapshotFetchOptions?: ISnapshotFetchOptions): Promise<ISnapshot> {
217
+ assert(this.hostPolicy.supportGetSnapshotApi !== true, "api should not be called yet");
218
+ // This is just temporary as this api is not yet enabled in service policies.
219
+ return this.fetchSnapshot(
220
+ this.hostPolicy.snapshotOptions,
221
+ snapshotFetchOptions?.scenarioName,
222
+ );
223
+ }
224
+
207
225
  public async getVersions(
208
226
  // eslint-disable-next-line @rushstack/no-new-null
209
227
  blobid: string | null,
@@ -233,16 +251,13 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
233
251
  // If count is one, we can use the trees/latest API, which returns the latest version and trees in a single request for better performance
234
252
  if (count === 1 && (blobid === null || blobid === this.documentId)) {
235
253
  const hostSnapshotOptions = this.hostPolicy.snapshotOptions;
236
- const odspSnapshotCacheValue: ISnapshotContents = await PerformanceEvent.timedExecAsync(
254
+ const odspSnapshotCacheValue: ISnapshot = await PerformanceEvent.timedExecAsync(
237
255
  this.logger,
238
256
  { eventName: "ObtainSnapshot", fetchSource },
239
257
  async (event: PerformanceEvent) => {
240
258
  const props: GetVersionsTelemetryProps = {};
241
259
  let cacheLookupTimeInSerialFetch = 0;
242
- let retrievedSnapshot:
243
- | ISnapshotContents
244
- | IPrefetchSnapshotContents
245
- | undefined;
260
+ let retrievedSnapshot: ISnapshot | IPrefetchSnapshotContents | undefined;
246
261
 
247
262
  let method: string;
248
263
  let prefetchWaitStartTime: number = performance.now();
@@ -255,10 +270,14 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
255
270
  } else {
256
271
  // Here's the logic to grab the persistent cache snapshot implemented by the host
257
272
  // Epoch tracker is responsible for communicating with the persistent cache, handling epochs and cache versions
258
- const cachedSnapshotP: Promise<ISnapshotContents | undefined> =
259
- this.epochTracker
260
- .get(createCacheSnapshotKey(this.odspResolvedUrl))
261
- .then(async (snapshotCachedEntry: ISnapshotCachedEntry) => {
273
+ const cachedSnapshotP: Promise<ISnapshot | undefined> = this.epochTracker
274
+ .get(createCacheSnapshotKey(this.odspResolvedUrl))
275
+ .then(
276
+ async (
277
+ snapshotCachedEntry:
278
+ | ISnapshotCachedEntry
279
+ | ISnapshotCachedEntry2,
280
+ ) => {
262
281
  if (snapshotCachedEntry !== undefined) {
263
282
  // If the cached entry does not contain the entry time, then assign it a default of 30 days old.
264
283
  const age =
@@ -281,10 +300,24 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
281
300
 
282
301
  // Record the cache age
283
302
  props.cacheEntryAge = age;
303
+ // Snapshot from cache could be in older format, so transform that before returning.
304
+ if (isInstanceOfISnapshot(snapshotCachedEntry)) {
305
+ return snapshotCachedEntry;
306
+ } else {
307
+ const snapshot: ISnapshot = {
308
+ snapshotTree: snapshotCachedEntry.snapshotTree,
309
+ blobContents: snapshotCachedEntry.blobs,
310
+ ops: snapshotCachedEntry.ops,
311
+ latestSequenceNumber:
312
+ snapshotCachedEntry.latestSequenceNumber,
313
+ sequenceNumber: snapshotCachedEntry.sequenceNumber,
314
+ snapshotFormatV: 1,
315
+ };
316
+ return snapshot;
317
+ }
284
318
  }
285
-
286
- return snapshotCachedEntry;
287
- });
319
+ },
320
+ );
288
321
  // Based on the concurrentSnapshotFetch policy:
289
322
  // Either retrieve both the network and cache snapshots concurrently and pick the first to return,
290
323
  // or grab the cache value and then the network value if the cache value returns undefined.
@@ -427,14 +460,14 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
427
460
  if (!versionsResponse) {
428
461
  throw new NonRetryableError(
429
462
  "No response from /versions endpoint",
430
- DriverErrorType.genericNetworkError,
463
+ OdspErrorTypes.genericNetworkError,
431
464
  { driverVersion },
432
465
  );
433
466
  }
434
467
  if (!Array.isArray(versionsResponse.value)) {
435
468
  throw new NonRetryableError(
436
469
  "Incorrect response from /versions endpoint, expected an array",
437
- DriverErrorType.genericNetworkError,
470
+ OdspErrorTypes.genericNetworkError,
438
471
  { driverVersion },
439
472
  );
440
473
  }
@@ -467,7 +500,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
467
500
  private async fetchSnapshotCore(
468
501
  hostSnapshotOptions: ISnapshotOptions | undefined,
469
502
  scenarioName?: string,
470
- ): Promise<ISnapshotContents | IPrefetchSnapshotContents> {
503
+ ): Promise<ISnapshot | IPrefetchSnapshotContents> {
471
504
  // Don't look into cache, if the host specifically tells us so.
472
505
  if (!this.hostPolicy.avoidPrefetchSnapshotCache) {
473
506
  const prefetchCacheKey = getKeyForCacheEntry(
@@ -554,7 +587,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
554
587
  const errorType = error.errorType;
555
588
  // If the snapshot size is too big and the host specified the size limitation(specified in hostSnapshotOptions), then don't try to fetch the snapshot again.
556
589
  if (
557
- errorType === OdspErrorType.snapshotTooBig &&
590
+ errorType === OdspErrorTypes.snapshotTooBig &&
558
591
  hostSnapshotOptions?.mds !== undefined &&
559
592
  this.hostPolicy.summarizerClient !== true
560
593
  ) {
@@ -562,8 +595,8 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
562
595
  }
563
596
  // If the first snapshot request was with blobs and we either timed out or the size was too big, then try to fetch without blobs.
564
597
  if (
565
- (errorType === OdspErrorType.snapshotTooBig ||
566
- errorType === OdspErrorType.fetchTimeout) &&
598
+ (errorType === OdspErrorTypes.snapshotTooBig ||
599
+ errorType === OdspErrorTypes.fetchTimeout) &&
567
600
  snapshotOptions.blobs
568
601
  ) {
569
602
  this.logger.sendErrorEvent({
@@ -684,7 +717,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
684
717
  if (!this.snapshotUrl) {
685
718
  throw new NonRetryableError(
686
719
  "Method failed because no snapshot url was available",
687
- DriverErrorType.genericError,
720
+ OdspErrorTypes.genericError,
688
721
  { driverVersion },
689
722
  );
690
723
  }
@@ -694,7 +727,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
694
727
  if (!this.attachmentPOSTUrl) {
695
728
  throw new NonRetryableError(
696
729
  "Method failed because no attachment POST url was available",
697
- DriverErrorType.genericError,
730
+ OdspErrorTypes.genericError,
698
731
  { driverVersion },
699
732
  );
700
733
  }
@@ -704,7 +737,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
704
737
  if (!this.attachmentGETUrl) {
705
738
  throw new NonRetryableError(
706
739
  "Method failed because no attachment GET url was available",
707
- DriverErrorType.genericError,
740
+ OdspErrorTypes.genericError,
708
741
  { driverVersion },
709
742
  );
710
743
  }
@@ -746,8 +779,8 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
746
779
  treeId = snapshot.snapshotTree.id;
747
780
  this.setRootTree(treeId, snapshot.snapshotTree);
748
781
  }
749
- if (snapshot.blobs) {
750
- this.initBlobsCache(snapshot.blobs);
782
+ if (snapshot.blobContents) {
783
+ this.initBlobsCache(snapshot.blobContents);
751
784
  }
752
785
  // If the version id doesn't match with the id of the tree, then use the id of first tree which in that case
753
786
  // will be the actual id of tree to be fetched.
@@ -11,10 +11,11 @@ import {
11
11
  LoaderCachingPolicy,
12
12
  FiveDaysMs,
13
13
  FetchSource,
14
+ ISnapshot,
15
+ ISnapshotFetchOptions,
14
16
  } from "@fluidframework/driver-definitions";
15
17
  import * as api from "@fluidframework/protocol-definitions";
16
18
  import { IConfigProvider } from "@fluidframework/telemetry-utils";
17
- import { ISnapshotContents } from "./odspPublicUtils";
18
19
 
19
20
  const maximumCacheDurationMs: FiveDaysMs = 432000000; // 5 * 24 * 60 * 60 * 1000 = 5 days in ms
20
21
 
@@ -208,6 +209,8 @@ export abstract class OdspDocumentStorageServiceBase implements IDocumentStorage
208
209
  return this.combineProtocolAndAppSnapshotTree(appTree, protocolTree);
209
210
  }
210
211
 
212
+ public abstract getSnapshot(snapshotFetchOptions?: ISnapshotFetchOptions): Promise<ISnapshot>;
213
+
211
214
  public abstract getVersions(
212
215
  // eslint-disable-next-line @rushstack/no-new-null
213
216
  blobid: string | null,
@@ -267,11 +270,11 @@ export abstract class OdspDocumentStorageServiceBase implements IDocumentStorage
267
270
  }
268
271
 
269
272
  protected initializeFromSnapshot(
270
- odspSnapshotCacheValue: ISnapshotContents,
273
+ odspSnapshotCacheValue: ISnapshot,
271
274
  cacheOps: boolean = true,
272
275
  ): string | undefined {
273
276
  this._snapshotSequenceNumber = odspSnapshotCacheValue.sequenceNumber;
274
- const { snapshotTree, blobs, ops } = odspSnapshotCacheValue;
277
+ const { snapshotTree, blobContents, ops } = odspSnapshotCacheValue;
275
278
 
276
279
  // id should be undefined in case of just ops in snapshot.
277
280
  let id: string | undefined;
@@ -281,8 +284,8 @@ export abstract class OdspDocumentStorageServiceBase implements IDocumentStorage
281
284
  this.setRootTree(id, snapshotTree);
282
285
  }
283
286
 
284
- if (blobs) {
285
- this.initBlobsCache(blobs);
287
+ if (blobContents) {
288
+ this.initBlobsCache(blobContents);
286
289
  }
287
290
 
288
291
  if (cacheOps) {
@@ -5,17 +5,12 @@
5
5
  import { assert } from "@fluidframework/core-utils";
6
6
  import { IRequest } from "@fluidframework/core-interfaces";
7
7
  import {
8
- DriverErrorType,
9
8
  DriverHeader,
10
9
  IContainerPackageInfo,
11
10
  IResolvedUrl,
12
11
  IUrlResolver,
13
12
  } from "@fluidframework/driver-definitions";
14
- import {
15
- IOdspResolvedUrl,
16
- ShareLinkTypes,
17
- ShareLinkInfoType,
18
- } from "@fluidframework/odsp-driver-definitions";
13
+ import { IOdspResolvedUrl, OdspErrorTypes } from "@fluidframework/odsp-driver-definitions";
19
14
  import { NonRetryableError } from "@fluidframework/driver-utils";
20
15
  import { createOdspUrl } from "./createOdspUrl";
21
16
  import { getApiRoot } from "./odspUrlHelper";
@@ -97,23 +92,14 @@ export class OdspDriverUrlResolver implements IUrlResolver {
97
92
  const driveID = searchParams.get("driveId");
98
93
  const filePath = searchParams.get("path");
99
94
  const packageName = searchParams.get("containerPackageName");
100
- const createLinkType = searchParams.get("createLinkType");
101
95
  // eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- false positive
102
96
  if (!(fileName && siteURL && driveID && filePath !== null && filePath !== undefined)) {
103
97
  throw new NonRetryableError(
104
98
  "Proper new file params should be there!!",
105
- DriverErrorType.genericError,
99
+ OdspErrorTypes.genericError,
106
100
  { driverVersion: pkgVersion },
107
101
  );
108
102
  }
109
- let shareLinkInfo: ShareLinkInfoType | undefined;
110
- if (createLinkType && createLinkType in ShareLinkTypes) {
111
- shareLinkInfo = {
112
- createLink: {
113
- type: ShareLinkTypes[createLinkType],
114
- },
115
- };
116
- }
117
103
  return {
118
104
  endpoints: {
119
105
  snapshotStorageUrl: "",
@@ -136,7 +122,7 @@ export class OdspDriverUrlResolver implements IUrlResolver {
136
122
  containerPackageName: packageName ?? undefined,
137
123
  },
138
124
  fileVersion: undefined,
139
- shareLinkInfo,
125
+ shareLinkInfo: undefined,
140
126
  isClpCompliantApp: request.headers?.[ClpCompliantAppHeader.isClpCompliantApp],
141
127
  };
142
128
  }
package/src/odspError.ts CHANGED
@@ -4,9 +4,8 @@
4
4
  */
5
5
 
6
6
  import { createOdspNetworkError } from "@fluidframework/odsp-doclib-utils";
7
- import { DriverErrorType } from "@fluidframework/driver-definitions";
8
7
  import { NonRetryableError } from "@fluidframework/driver-utils";
9
- import { OdspError } from "@fluidframework/odsp-driver-definitions";
8
+ import { OdspError, OdspErrorTypes } from "@fluidframework/odsp-driver-definitions";
10
9
  import { getCircularReplacer, IFluidErrorBase } from "@fluidframework/telemetry-utils";
11
10
  import { IOdspSocketError } from "./contracts";
12
11
  import { pkgVersion as driverVersion } from "./packageVersion";
@@ -37,7 +36,7 @@ export function errorObjectFromSocketError(
37
36
  } catch (error) {
38
37
  return new NonRetryableError(
39
38
  "Internal error: errorObjectFromSocketError",
40
- DriverErrorType.fileNotFoundOrAccessDeniedError,
39
+ OdspErrorTypes.fileNotFoundOrAccessDeniedError,
41
40
  { driverVersion },
42
41
  );
43
42
  }
@@ -16,6 +16,7 @@ export async function getHashedDocumentId(driveId: string, itemId: string): Prom
16
16
 
17
17
  /**
18
18
  * @alpha
19
+ * @deprecated - This is deprecated.
19
20
  */
20
21
  export interface ISnapshotContents {
21
22
  snapshotTree: ISnapshotTree;
@@ -6,8 +6,8 @@
6
6
  import { stringToBuffer } from "@fluid-internal/client-utils";
7
7
  import { assert } from "@fluidframework/core-utils";
8
8
  import * as api from "@fluidframework/protocol-definitions";
9
+ import { ISnapshot } from "@fluidframework/driver-definitions";
9
10
  import { IOdspSnapshot, IOdspSnapshotCommit } from "./contracts";
10
- import { ISnapshotContents } from "./odspPublicUtils";
11
11
 
12
12
  /**
13
13
  * Build a tree hierarchy base on a flat tree
@@ -51,9 +51,7 @@ function buildHierarchy(flatTree: IOdspSnapshotCommit): api.ISnapshotTree {
51
51
  * Converts existing IOdspSnapshot to snapshot tree, blob array and ops
52
52
  * @param odspSnapshot - snapshot
53
53
  */
54
- export function convertOdspSnapshotToSnapshotTreeAndBlobs(
55
- odspSnapshot: IOdspSnapshot,
56
- ): ISnapshotContents {
54
+ export function convertOdspSnapshotToSnapshotTreeAndBlobs(odspSnapshot: IOdspSnapshot): ISnapshot {
57
55
  const blobsWithBufferContent = new Map<string, ArrayBuffer>();
58
56
  if (odspSnapshot.blobs) {
59
57
  odspSnapshot.blobs.forEach((blob) => {
@@ -70,8 +68,8 @@ export function convertOdspSnapshotToSnapshotTreeAndBlobs(
70
68
 
71
69
  const sequenceNumber = odspSnapshot?.trees[0].sequenceNumber;
72
70
 
73
- const val: ISnapshotContents = {
74
- blobs: blobsWithBufferContent,
71
+ const val: ISnapshot = {
72
+ blobContents: blobsWithBufferContent,
75
73
  ops: odspSnapshot.ops?.map((op) => op.op) ?? [],
76
74
  sequenceNumber,
77
75
  snapshotTree: buildHierarchy(odspSnapshot.trees[0]),
@@ -79,6 +77,7 @@ export function convertOdspSnapshotToSnapshotTreeAndBlobs(
79
77
  odspSnapshot.ops && odspSnapshot.ops.length > 0
80
78
  ? odspSnapshot.ops[odspSnapshot.ops.length - 1].sequenceNumber
81
79
  : sequenceNumber,
80
+ snapshotFormatV: 1,
82
81
  };
83
82
  return val;
84
83
  }