@fluidframework/container-loader 2.0.0-dev-rc.5.0.0.265721 → 2.0.0-dev-rc.5.0.0.268409

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 (165) hide show
  1. package/api-report/{container-loader.api.md → container-loader.alpha.api.md} +7 -17
  2. package/api-report/container-loader.beta.api.md +40 -0
  3. package/api-report/container-loader.public.api.md +40 -0
  4. package/dist/attachment.d.ts +1 -1
  5. package/dist/attachment.d.ts.map +1 -1
  6. package/dist/attachment.js.map +1 -1
  7. package/dist/audience.d.ts +1 -1
  8. package/dist/audience.d.ts.map +1 -1
  9. package/dist/audience.js.map +1 -1
  10. package/dist/catchUpMonitor.js.map +1 -1
  11. package/dist/connectionManager.d.ts +2 -2
  12. package/dist/connectionManager.d.ts.map +1 -1
  13. package/dist/connectionManager.js +3 -4
  14. package/dist/connectionManager.js.map +1 -1
  15. package/dist/connectionStateHandler.d.ts +4 -2
  16. package/dist/connectionStateHandler.d.ts.map +1 -1
  17. package/dist/connectionStateHandler.js +18 -12
  18. package/dist/connectionStateHandler.js.map +1 -1
  19. package/dist/container.d.ts +2 -2
  20. package/dist/container.d.ts.map +1 -1
  21. package/dist/container.js +84 -67
  22. package/dist/container.js.map +1 -1
  23. package/dist/containerContext.d.ts +2 -2
  24. package/dist/containerContext.d.ts.map +1 -1
  25. package/dist/containerContext.js.map +1 -1
  26. package/dist/containerStorageAdapter.d.ts +2 -2
  27. package/dist/containerStorageAdapter.d.ts.map +1 -1
  28. package/dist/containerStorageAdapter.js +7 -2
  29. package/dist/containerStorageAdapter.js.map +1 -1
  30. package/dist/contracts.d.ts +2 -2
  31. package/dist/contracts.d.ts.map +1 -1
  32. package/dist/contracts.js.map +1 -1
  33. package/dist/debugLogger.d.ts.map +1 -1
  34. package/dist/debugLogger.js.map +1 -1
  35. package/dist/deltaManager.d.ts +4 -4
  36. package/dist/deltaManager.d.ts.map +1 -1
  37. package/dist/deltaManager.js +8 -9
  38. package/dist/deltaManager.js.map +1 -1
  39. package/dist/loadPaused.js.map +1 -1
  40. package/dist/loader.d.ts +8 -1
  41. package/dist/loader.d.ts.map +1 -1
  42. package/dist/loader.js.map +1 -1
  43. package/dist/memoryBlobStorage.d.ts +9 -0
  44. package/dist/memoryBlobStorage.d.ts.map +1 -0
  45. package/dist/memoryBlobStorage.js +58 -0
  46. package/dist/memoryBlobStorage.js.map +1 -0
  47. package/dist/noopHeuristic.d.ts +1 -1
  48. package/dist/noopHeuristic.d.ts.map +1 -1
  49. package/dist/noopHeuristic.js.map +1 -1
  50. package/dist/packageVersion.d.ts +1 -1
  51. package/dist/packageVersion.js +1 -1
  52. package/dist/packageVersion.js.map +1 -1
  53. package/dist/protocol.d.ts +2 -1
  54. package/dist/protocol.d.ts.map +1 -1
  55. package/dist/protocol.js +4 -4
  56. package/dist/protocol.js.map +1 -1
  57. package/dist/protocolTreeDocumentStorageService.d.ts +5 -5
  58. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  59. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  60. package/dist/quorum.d.ts +1 -1
  61. package/dist/quorum.d.ts.map +1 -1
  62. package/dist/quorum.js.map +1 -1
  63. package/dist/retriableDocumentStorageService.d.ts +2 -2
  64. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  65. package/dist/retriableDocumentStorageService.js.map +1 -1
  66. package/dist/serializedStateManager.d.ts +5 -3
  67. package/dist/serializedStateManager.d.ts.map +1 -1
  68. package/dist/serializedStateManager.js.map +1 -1
  69. package/dist/utils.d.ts +2 -1
  70. package/dist/utils.d.ts.map +1 -1
  71. package/dist/utils.js +7 -7
  72. package/dist/utils.js.map +1 -1
  73. package/lib/attachment.d.ts +1 -1
  74. package/lib/attachment.d.ts.map +1 -1
  75. package/lib/attachment.js.map +1 -1
  76. package/lib/audience.d.ts +1 -1
  77. package/lib/audience.d.ts.map +1 -1
  78. package/lib/audience.js.map +1 -1
  79. package/lib/catchUpMonitor.js.map +1 -1
  80. package/lib/connectionManager.d.ts +2 -2
  81. package/lib/connectionManager.d.ts.map +1 -1
  82. package/lib/connectionManager.js +1 -2
  83. package/lib/connectionManager.js.map +1 -1
  84. package/lib/connectionStateHandler.d.ts +4 -2
  85. package/lib/connectionStateHandler.d.ts.map +1 -1
  86. package/lib/connectionStateHandler.js +19 -13
  87. package/lib/connectionStateHandler.js.map +1 -1
  88. package/lib/container.d.ts +2 -2
  89. package/lib/container.d.ts.map +1 -1
  90. package/lib/container.js +26 -9
  91. package/lib/container.js.map +1 -1
  92. package/lib/containerContext.d.ts +2 -2
  93. package/lib/containerContext.d.ts.map +1 -1
  94. package/lib/containerContext.js.map +1 -1
  95. package/lib/containerStorageAdapter.d.ts +2 -2
  96. package/lib/containerStorageAdapter.d.ts.map +1 -1
  97. package/lib/containerStorageAdapter.js +7 -2
  98. package/lib/containerStorageAdapter.js.map +1 -1
  99. package/lib/contracts.d.ts +2 -2
  100. package/lib/contracts.d.ts.map +1 -1
  101. package/lib/contracts.js.map +1 -1
  102. package/lib/debugLogger.d.ts.map +1 -1
  103. package/lib/debugLogger.js.map +1 -1
  104. package/lib/deltaManager.d.ts +4 -4
  105. package/lib/deltaManager.d.ts.map +1 -1
  106. package/lib/deltaManager.js +1 -2
  107. package/lib/deltaManager.js.map +1 -1
  108. package/lib/loadPaused.js.map +1 -1
  109. package/lib/loader.d.ts +8 -1
  110. package/lib/loader.d.ts.map +1 -1
  111. package/lib/loader.js.map +1 -1
  112. package/lib/memoryBlobStorage.d.ts +9 -0
  113. package/lib/memoryBlobStorage.d.ts.map +1 -0
  114. package/lib/memoryBlobStorage.js +52 -0
  115. package/lib/memoryBlobStorage.js.map +1 -0
  116. package/lib/noopHeuristic.d.ts +1 -1
  117. package/lib/noopHeuristic.d.ts.map +1 -1
  118. package/lib/noopHeuristic.js.map +1 -1
  119. package/lib/packageVersion.d.ts +1 -1
  120. package/lib/packageVersion.js +1 -1
  121. package/lib/packageVersion.js.map +1 -1
  122. package/lib/protocol.d.ts +2 -1
  123. package/lib/protocol.d.ts.map +1 -1
  124. package/lib/protocol.js +1 -1
  125. package/lib/protocol.js.map +1 -1
  126. package/lib/protocolTreeDocumentStorageService.d.ts +5 -5
  127. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  128. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  129. package/lib/quorum.d.ts +1 -1
  130. package/lib/quorum.d.ts.map +1 -1
  131. package/lib/quorum.js.map +1 -1
  132. package/lib/retriableDocumentStorageService.d.ts +2 -2
  133. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  134. package/lib/retriableDocumentStorageService.js.map +1 -1
  135. package/lib/serializedStateManager.d.ts +5 -3
  136. package/lib/serializedStateManager.d.ts.map +1 -1
  137. package/lib/serializedStateManager.js.map +1 -1
  138. package/lib/tsdoc-metadata.json +1 -1
  139. package/lib/utils.d.ts +2 -1
  140. package/lib/utils.d.ts.map +1 -1
  141. package/lib/utils.js +2 -2
  142. package/lib/utils.js.map +1 -1
  143. package/package.json +14 -15
  144. package/src/attachment.ts +3 -1
  145. package/src/audience.ts +1 -1
  146. package/src/catchUpMonitor.ts +1 -1
  147. package/src/connectionManager.ts +16 -16
  148. package/src/connectionStateHandler.ts +27 -19
  149. package/src/container.ts +51 -27
  150. package/src/containerContext.ts +6 -3
  151. package/src/containerStorageAdapter.ts +7 -6
  152. package/src/contracts.ts +7 -5
  153. package/src/debugLogger.ts +2 -3
  154. package/src/deltaManager.ts +7 -7
  155. package/src/loadPaused.ts +1 -1
  156. package/src/loader.ts +9 -1
  157. package/src/memoryBlobStorage.ts +80 -0
  158. package/src/noopHeuristic.ts +1 -1
  159. package/src/packageVersion.ts +1 -1
  160. package/src/protocol.ts +7 -8
  161. package/src/protocolTreeDocumentStorageService.ts +1 -1
  162. package/src/quorum.ts +1 -1
  163. package/src/retriableDocumentStorageService.ts +3 -6
  164. package/src/serializedStateManager.ts +8 -7
  165. package/src/utils.ts +6 -7
package/src/container.ts CHANGED
@@ -37,6 +37,16 @@ import {
37
37
  } from "@fluidframework/core-interfaces";
38
38
  import { type ISignalEnvelope } from "@fluidframework/core-interfaces/internal";
39
39
  import { assert, isPromiseLike, unreachableCase } from "@fluidframework/core-utils/internal";
40
+ import {
41
+ IClient,
42
+ IClientDetails,
43
+ IQuorumClients,
44
+ ISequencedClient,
45
+ ISequencedDocumentMessage,
46
+ ISignalMessage,
47
+ ISummaryTree,
48
+ SummaryType,
49
+ } from "@fluidframework/driver-definitions";
40
50
  import {
41
51
  IDocumentService,
42
52
  IDocumentServiceFactory,
@@ -45,6 +55,15 @@ import {
45
55
  ISnapshot,
46
56
  IThrottlingWarning,
47
57
  IUrlResolver,
58
+ ICommittedProposal,
59
+ IDocumentAttributes,
60
+ IDocumentMessage,
61
+ IQuorumProposals,
62
+ ISequencedProposal,
63
+ ISnapshotTree,
64
+ ISummaryContent,
65
+ IVersion,
66
+ MessageType,
48
67
  } from "@fluidframework/driver-definitions/internal";
49
68
  import {
50
69
  getSnapshotTree,
@@ -57,25 +76,6 @@ import {
57
76
  runWithRetry,
58
77
  } from "@fluidframework/driver-utils/internal";
59
78
  import { IQuorumSnapshot } from "@fluidframework/protocol-base";
60
- import {
61
- IClient,
62
- IClientDetails,
63
- ICommittedProposal,
64
- IDocumentAttributes,
65
- IDocumentMessage,
66
- IQuorumClients,
67
- IQuorumProposals,
68
- ISequencedClient,
69
- ISequencedDocumentMessage,
70
- ISequencedProposal,
71
- ISignalMessage,
72
- ISnapshotTree,
73
- ISummaryContent,
74
- ISummaryTree,
75
- IVersion,
76
- MessageType,
77
- SummaryType,
78
- } from "@fluidframework/protocol-definitions";
79
79
  import {
80
80
  type TelemetryEventCategory,
81
81
  ITelemetryLoggerExt,
@@ -92,6 +92,7 @@ import {
92
92
  normalizeError,
93
93
  raiseConnectedEvent,
94
94
  wrapError,
95
+ loggerToMonitoringContext,
95
96
  } from "@fluidframework/telemetry-utils/internal";
96
97
  import structuredClone from "@ungap/structured-clone";
97
98
  import { v4 as uuid } from "uuid";
@@ -111,7 +112,13 @@ import {
111
112
  getPackageName,
112
113
  } from "./contracts.js";
113
114
  import { DeltaManager, IConnectionArgs } from "./deltaManager.js";
115
+ // eslint-disable-next-line import/no-deprecated
114
116
  import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader.js";
117
+ import {
118
+ serializeMemoryDetachedBlobStorage,
119
+ createMemoryDetachedBlobStorage,
120
+ tryInitializeMemoryDetachedBlobStorage,
121
+ } from "./memoryBlobStorage.js";
115
122
  import { NoopHeuristic } from "./noopHeuristic.js";
116
123
  import { pkgVersion } from "./packageVersion.js";
117
124
  import {
@@ -218,6 +225,7 @@ export interface IContainerCreateProps {
218
225
  /**
219
226
  * Blobs storage for detached containers.
220
227
  */
228
+ // eslint-disable-next-line import/no-deprecated
221
229
  readonly detachedBlobStorage?: IDetachedBlobStorage;
222
230
 
223
231
  /**
@@ -465,7 +473,8 @@ export class Container
465
473
  private readonly options: ILoaderOptions;
466
474
  private readonly scope: FluidObject;
467
475
  private readonly subLogger: ITelemetryLoggerExt;
468
- private readonly detachedBlobStorage: IDetachedBlobStorage | undefined;
476
+ // eslint-disable-next-line import/no-deprecated
477
+ private readonly detachedBlobStorage: IDetachedBlobStorage;
469
478
  private readonly protocolHandlerBuilder: ProtocolHandlerBuilder;
470
479
  private readonly client: IClient;
471
480
 
@@ -517,6 +526,15 @@ export class Container
517
526
  0x969 /* not connected yet */,
518
527
  );
519
528
 
529
+ // Track membership changes and update connection state accordingly
530
+ // We do this call here, instead of doing it in initializeProtocolState() due to pendingLocalState.
531
+ // When we load from stashed state, we let connectionStateHandler know about clientId from previous container instance.
532
+ // But we will play trailing ops from snapshot, including potentially playing join & leave ops for that same clientId!
533
+ // In other words, if connectionStateHandler has access to Quorum early in load sequence, it will see events (in stashed ops mode)
534
+ // in the order that is not possible in real life, that it may not expect.
535
+ // Ideally, we should supply pendingLocalState?.clientId here as well, not in constructor, but it does not matter (at least today)
536
+ this.connectionStateHandler.initProtocol(this.protocolHandler);
537
+
520
538
  // Propagate current connection state through the system.
521
539
  const readonly = this.readOnlyInfo.readonly ?? false;
522
540
  // This call does not look like needed any more, with delaying all connection-related events past loaded phase.
@@ -767,7 +785,7 @@ export class Container
767
785
  // Tracking alternative ways to handle this in AB#4129.
768
786
  this.options = { ...options };
769
787
  this.scope = scope;
770
- this.detachedBlobStorage = detachedBlobStorage;
788
+ this.detachedBlobStorage = detachedBlobStorage ?? createMemoryDetachedBlobStorage();
771
789
  this.protocolHandlerBuilder =
772
790
  protocolHandlerBuilder ??
773
791
  ((
@@ -856,6 +874,9 @@ export class Container
856
874
  this.connectionStateHandler = createConnectionStateHandler(
857
875
  {
858
876
  logger: this.mc.logger,
877
+ // WARNING: logger on this context should not including getters like containerConnectionState above (on this.subLogger),
878
+ // as that will result in attempt to dereference this.connectionStateHandler from this call while it's still undefined.
879
+ mc: loggerToMonitoringContext(subLogger),
859
880
  connectionStateChanged: (value, oldState, reason) => {
860
881
  this.logConnectionStateChangeTelemetry(value, oldState, reason);
861
882
  if (this.loaded) {
@@ -944,7 +965,7 @@ export class Container
944
965
  options.summarizeProtocolTree;
945
966
 
946
967
  this.storageAdapter = new ContainerStorageAdapter(
947
- detachedBlobStorage,
968
+ this.detachedBlobStorage,
948
969
  this.mc.logger,
949
970
  pendingLocalState?.snapshotBlobs,
950
971
  pendingLocalState?.loadedGroupIdSnapshots,
@@ -1208,7 +1229,8 @@ export class Container
1208
1229
  baseSnapshot,
1209
1230
  snapshotBlobs,
1210
1231
  pendingRuntimeState,
1211
- hasAttachmentBlobs: !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
1232
+ hasAttachmentBlobs: this.detachedBlobStorage.size > 0,
1233
+ attachmentBlobs: serializeMemoryDetachedBlobStorage(this.detachedBlobStorage),
1212
1234
  };
1213
1235
  return JSON.stringify(detachedContainerState);
1214
1236
  }
@@ -1328,6 +1350,7 @@ export class Container
1328
1350
  this.serializedStateManager.setInitialSnapshot(snapshotWithBlobs);
1329
1351
 
1330
1352
  if (!this.closed) {
1353
+ this.detachedBlobStorage.dispose?.();
1331
1354
  this.handleDeltaConnectionArg(attachProps?.deltaConnection, {
1332
1355
  fetchOpsFromStorage: false,
1333
1356
  reason: { text: "createDetached" },
@@ -1760,11 +1783,15 @@ export class Container
1760
1783
  baseSnapshot,
1761
1784
  snapshotBlobs,
1762
1785
  hasAttachmentBlobs,
1786
+ attachmentBlobs,
1763
1787
  pendingRuntimeState,
1764
1788
  }: IPendingDetachedContainerState) {
1765
1789
  if (hasAttachmentBlobs) {
1790
+ if (attachmentBlobs !== undefined) {
1791
+ tryInitializeMemoryDetachedBlobStorage(this.detachedBlobStorage, attachmentBlobs);
1792
+ }
1766
1793
  assert(
1767
- !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
1794
+ this.detachedBlobStorage.size > 0,
1768
1795
  0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
1769
1796
  );
1770
1797
  }
@@ -1853,9 +1880,6 @@ export class Container
1853
1880
  protocolLogger.sendErrorEvent(error);
1854
1881
  });
1855
1882
 
1856
- // Track membership changes and update connection state accordingly
1857
- this.connectionStateHandler.initProtocol(protocol);
1858
-
1859
1883
  protocol.quorum.on("addProposal", (proposal: ISequencedProposal) => {
1860
1884
  if (proposal.key === "code" || proposal.key === "code2") {
1861
1885
  this.emit("codeDetailsProposed", proposal.value, proposal);
@@ -17,17 +17,20 @@ import {
17
17
  } from "@fluidframework/container-definitions/internal";
18
18
  import { type FluidObject } from "@fluidframework/core-interfaces";
19
19
  import { type ISignalEnvelope } from "@fluidframework/core-interfaces/internal";
20
- import { IDocumentStorageService, ISnapshot } from "@fluidframework/driver-definitions/internal";
21
20
  import {
22
21
  IClientDetails,
23
- IDocumentMessage,
24
22
  IQuorumClients,
25
23
  ISequencedDocumentMessage,
24
+ } from "@fluidframework/driver-definitions";
25
+ import {
26
+ IDocumentStorageService,
27
+ ISnapshot,
28
+ IDocumentMessage,
26
29
  ISnapshotTree,
27
30
  ISummaryContent,
28
31
  IVersion,
29
32
  MessageType,
30
- } from "@fluidframework/protocol-definitions";
33
+ } from "@fluidframework/driver-definitions/internal";
31
34
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
32
35
 
33
36
  /**
@@ -7,6 +7,7 @@ import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
7
7
  import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions/internal";
8
8
  import { IDisposable } from "@fluidframework/core-interfaces";
9
9
  import { assert } from "@fluidframework/core-utils/internal";
10
+ import { ISummaryHandle, ISummaryTree } from "@fluidframework/driver-definitions";
10
11
  import {
11
12
  FetchSource,
12
13
  IDocumentService,
@@ -15,17 +16,14 @@ import {
15
16
  ISnapshot,
16
17
  ISnapshotFetchOptions,
17
18
  ISummaryContext,
18
- } from "@fluidframework/driver-definitions/internal";
19
- import { UsageError } from "@fluidframework/driver-utils/internal";
20
- import {
21
19
  ICreateBlobResponse,
22
20
  ISnapshotTree,
23
- ISummaryHandle,
24
- ISummaryTree,
25
21
  IVersion,
26
- } from "@fluidframework/protocol-definitions";
22
+ } from "@fluidframework/driver-definitions/internal";
23
+ import { UsageError } from "@fluidframework/driver-utils/internal";
27
24
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
28
25
 
26
+ // eslint-disable-next-line import/no-deprecated
29
27
  import { IDetachedBlobStorage } from "./loader.js";
30
28
  import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService.js";
31
29
  import { RetriableDocumentStorageService } from "./retriableDocumentStorageService.js";
@@ -79,6 +77,7 @@ export class ContainerStorageAdapter
79
77
  * @param forceEnableSummarizeProtocolTree - Enforce uploading a protocol summary regardless of the service's policy
80
78
  */
81
79
  public constructor(
80
+ // eslint-disable-next-line import/no-deprecated
82
81
  detachedBlobStorage: IDetachedBlobStorage | undefined,
83
82
  private readonly logger: ITelemetryLoggerExt,
84
83
  /**
@@ -233,6 +232,7 @@ export class ContainerStorageAdapter
233
232
  */
234
233
  class BlobOnlyStorage implements IDocumentStorageService {
235
234
  constructor(
235
+ // eslint-disable-next-line import/no-deprecated
236
236
  private readonly detachedStorage: IDetachedBlobStorage | undefined,
237
237
  private readonly logger: ITelemetryLoggerExt,
238
238
  ) {}
@@ -245,6 +245,7 @@ class BlobOnlyStorage implements IDocumentStorageService {
245
245
  return this.verifyStorage().readBlob(blobId);
246
246
  }
247
247
 
248
+ // eslint-disable-next-line import/no-deprecated
248
249
  private verifyStorage(): IDetachedBlobStorage {
249
250
  if (this.detachedStorage === undefined) {
250
251
  throw new UsageError("Real storage calls not allowed in Unattached container");
package/src/contracts.ts CHANGED
@@ -12,16 +12,18 @@ import {
12
12
  IConnectionDetails,
13
13
  } from "@fluidframework/container-definitions/internal";
14
14
  import { IErrorBase, ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
15
- import { IContainerPackageInfo } from "@fluidframework/driver-definitions/internal";
16
15
  import {
17
16
  ConnectionMode,
18
- IClientConfiguration,
19
17
  IClientDetails,
20
- IDocumentMessage,
21
18
  ISequencedDocumentMessage,
22
- ISignalClient,
23
19
  ISignalMessage,
24
- } from "@fluidframework/protocol-definitions";
20
+ } from "@fluidframework/driver-definitions";
21
+ import {
22
+ IContainerPackageInfo,
23
+ IClientConfiguration,
24
+ IDocumentMessage,
25
+ ISignalClient,
26
+ } from "@fluidframework/driver-definitions/internal";
25
27
 
26
28
  export enum ReconnectMode {
27
29
  Never = "Never",
@@ -16,13 +16,12 @@ import {
16
16
  eventNamespaceSeparator,
17
17
  formatTick,
18
18
  } from "@fluidframework/telemetry-utils/internal";
19
-
20
19
  // This import style is necessary to ensure the emitted JS code works in both CJS and ESM.
21
20
  import debugPkg from "debug";
22
- const { debug: registerDebug } = debugPkg;
23
-
24
21
  import type { IDebugger } from "debug";
25
22
 
23
+ const { debug: registerDebug } = debugPkg;
24
+
26
25
  /**
27
26
  * Implementation of debug logger
28
27
  */
@@ -16,23 +16,23 @@ import {
16
16
  } from "@fluidframework/core-interfaces";
17
17
  import { IThrottlingWarning } from "@fluidframework/core-interfaces/internal";
18
18
  import { assert } from "@fluidframework/core-utils/internal";
19
+ import {
20
+ ConnectionMode,
21
+ ISequencedDocumentMessage,
22
+ ISignalMessage,
23
+ } from "@fluidframework/driver-definitions";
19
24
  import {
20
25
  IDocumentDeltaStorageService,
21
26
  IDocumentService,
22
27
  DriverErrorTypes,
28
+ IDocumentMessage,
29
+ MessageType,
23
30
  } from "@fluidframework/driver-definitions/internal";
24
31
  import {
25
32
  MessageType2,
26
33
  NonRetryableError,
27
34
  isRuntimeMessage,
28
35
  } from "@fluidframework/driver-utils/internal";
29
- import {
30
- ConnectionMode,
31
- IDocumentMessage,
32
- ISequencedDocumentMessage,
33
- ISignalMessage,
34
- MessageType,
35
- } from "@fluidframework/protocol-definitions";
36
36
  import {
37
37
  type ITelemetryErrorEventExt,
38
38
  type ITelemetryGenericEventExt,
package/src/loadPaused.ts CHANGED
@@ -5,8 +5,8 @@
5
5
 
6
6
  import { ILoader, LoaderHeader } from "@fluidframework/container-definitions/internal";
7
7
  import { IRequest } from "@fluidframework/core-interfaces";
8
- import { GenericError } from "@fluidframework/telemetry-utils/internal";
9
8
  import type { IErrorBase } from "@fluidframework/core-interfaces";
9
+ import { GenericError } from "@fluidframework/telemetry-utils/internal";
10
10
 
11
11
  /* eslint-disable jsdoc/check-indentation */
12
12
 
package/src/loader.ts CHANGED
@@ -19,13 +19,13 @@ import {
19
19
  IRequest,
20
20
  ITelemetryBaseLogger,
21
21
  } from "@fluidframework/core-interfaces";
22
+ import { IClientDetails } from "@fluidframework/driver-definitions";
22
23
  import {
23
24
  IDocumentServiceFactory,
24
25
  IDocumentStorageService,
25
26
  IResolvedUrl,
26
27
  IUrlResolver,
27
28
  } from "@fluidframework/driver-definitions/internal";
28
- import { IClientDetails } from "@fluidframework/protocol-definitions";
29
29
  import {
30
30
  ITelemetryLoggerExt,
31
31
  MonitoringContext,
@@ -227,6 +227,7 @@ export interface ILoaderServices {
227
227
 
228
228
  /**
229
229
  * Blobs storage for detached containers.
230
+ * @deprecated - IDetachedBlobStorage will be removed in a future release without a replacement. Blobs created while detached will be stored in memory to align with attached container behavior. AB#8049
230
231
  */
231
232
  readonly detachedBlobStorage?: IDetachedBlobStorage;
232
233
 
@@ -241,6 +242,8 @@ export interface ILoaderServices {
241
242
  * Subset of IDocumentStorageService which only supports createBlob() and readBlob(). This is used to support
242
243
  * blobs in detached containers.
243
244
  * @alpha
245
+ *
246
+ * @deprecated - IDetachedBlobStorage will be removed in a future release without a replacement. Blobs created while detached will be stored in memory to align with attached container behavior. AB#8049
244
247
  */
245
248
  export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" | "readBlob"> & {
246
249
  size: number;
@@ -248,6 +251,11 @@ export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" |
248
251
  * Return an array of all blob IDs present in storage
249
252
  */
250
253
  getBlobIds(): string[];
254
+
255
+ /**
256
+ * After the container is attached, the detached blob storage is no longer needed and will be disposed.
257
+ */
258
+ dispose?(): void;
251
259
  };
252
260
 
253
261
  /**
@@ -0,0 +1,80 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
7
+ import { assert, isObject } from "@fluidframework/core-utils/internal";
8
+ import type { ICreateBlobResponse } from "@fluidframework/driver-definitions/internal";
9
+
10
+ // eslint-disable-next-line import/no-deprecated
11
+ import type { IDetachedBlobStorage } from "./loader.js";
12
+
13
+ const MemoryDetachedBlobStorageIdentifier = Symbol();
14
+
15
+ // eslint-disable-next-line import/no-deprecated
16
+ interface MemoryDetachedBlobStorage extends IDetachedBlobStorage {
17
+ [MemoryDetachedBlobStorageIdentifier]: typeof MemoryDetachedBlobStorageIdentifier;
18
+ initialize(attachmentBlobs: string[]): void;
19
+ serialize(): string | undefined;
20
+ }
21
+
22
+ function isMemoryDetachedBlobStorage(
23
+ // eslint-disable-next-line import/no-deprecated
24
+ detachedStorage: IDetachedBlobStorage,
25
+ ): detachedStorage is MemoryDetachedBlobStorage {
26
+ return (
27
+ isObject(detachedStorage) &&
28
+ MemoryDetachedBlobStorageIdentifier in detachedStorage &&
29
+ detachedStorage[MemoryDetachedBlobStorageIdentifier] === MemoryDetachedBlobStorageIdentifier
30
+ );
31
+ }
32
+
33
+ export function serializeMemoryDetachedBlobStorage(
34
+ // eslint-disable-next-line import/no-deprecated
35
+ detachedStorage: IDetachedBlobStorage,
36
+ ): string | undefined {
37
+ if (detachedStorage.size > 0 && isMemoryDetachedBlobStorage(detachedStorage)) {
38
+ return detachedStorage.serialize();
39
+ }
40
+ }
41
+
42
+ export function tryInitializeMemoryDetachedBlobStorage(
43
+ // eslint-disable-next-line import/no-deprecated
44
+ detachedStorage: IDetachedBlobStorage,
45
+ attachmentBlobs: string,
46
+ ) {
47
+ if (!isMemoryDetachedBlobStorage(detachedStorage)) {
48
+ throw new Error(
49
+ "DetachedBlobStorage was not provided to the loader during serialize so cannot be provided during rehydrate.",
50
+ );
51
+ }
52
+
53
+ assert(detachedStorage.size === 0, "Blob storage already initialized");
54
+ const maybeAttachmentBlobs = JSON.parse(attachmentBlobs);
55
+ assert(Array.isArray(maybeAttachmentBlobs), "Invalid attachmentBlobs");
56
+
57
+ detachedStorage.initialize(maybeAttachmentBlobs);
58
+ }
59
+
60
+ // eslint-disable-next-line import/no-deprecated
61
+ export function createMemoryDetachedBlobStorage(): IDetachedBlobStorage {
62
+ const blobs: ArrayBufferLike[] = [];
63
+ const storage: MemoryDetachedBlobStorage = {
64
+ [MemoryDetachedBlobStorageIdentifier]: MemoryDetachedBlobStorageIdentifier,
65
+ createBlob: async (file: ArrayBufferLike): Promise<ICreateBlobResponse> => ({
66
+ id: `${blobs.push(file) - 1}`,
67
+ }),
68
+ readBlob: async (id: string): Promise<ArrayBufferLike> =>
69
+ blobs[Number(id)] ?? Promise.reject(new Error(`Blob not found: ${id}`)),
70
+ get size() {
71
+ return blobs.length;
72
+ },
73
+ getBlobIds: (): string[] => blobs.map((_, i) => `${i}`),
74
+ dispose: () => blobs.splice(0),
75
+ serialize: () => JSON.stringify(blobs.map((b) => bufferToString(b, "utf-8"))),
76
+ initialize: (attachmentBlobs: string[]) =>
77
+ blobs.push(...attachmentBlobs.map((maybeBlob) => stringToBuffer(maybeBlob, "utf-8"))),
78
+ };
79
+ return storage;
80
+ }
@@ -6,8 +6,8 @@
6
6
  import { TypedEventEmitter } from "@fluid-internal/client-utils";
7
7
  import { IEvent } from "@fluidframework/core-interfaces";
8
8
  import { assert, Timer } from "@fluidframework/core-utils/internal";
9
+ import { ISequencedDocumentMessage } from "@fluidframework/driver-definitions";
9
10
  import { isRuntimeMessage } from "@fluidframework/driver-utils/internal";
10
- import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
11
11
 
12
12
  const defaultNoopTimeFrequency = 2000;
13
13
  const defaultNoopCountFrequency = 50;
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-dev-rc.5.0.0.265721";
9
+ export const pkgVersion = "2.0.0-dev-rc.5.0.0.268409";
package/src/protocol.ts CHANGED
@@ -4,20 +4,19 @@
4
4
  */
5
5
 
6
6
  import { IAudienceOwner } from "@fluidframework/container-definitions/internal";
7
+ import { ISequencedDocumentMessage, ISignalMessage } from "@fluidframework/driver-definitions";
8
+ import {
9
+ IDocumentAttributes,
10
+ IProcessMessageResult,
11
+ ISignalClient,
12
+ MessageType,
13
+ } from "@fluidframework/driver-definitions/internal";
7
14
  import { canBeCoalescedByService } from "@fluidframework/driver-utils/internal";
8
15
  import {
9
16
  IProtocolHandler as IBaseProtocolHandler,
10
17
  IQuorumSnapshot,
11
18
  ProtocolOpHandler,
12
19
  } from "@fluidframework/protocol-base";
13
- import {
14
- IDocumentAttributes,
15
- IProcessMessageResult,
16
- ISequencedDocumentMessage,
17
- ISignalClient,
18
- ISignalMessage,
19
- MessageType,
20
- } from "@fluidframework/protocol-definitions";
21
20
 
22
21
  // ADO: #1986: Start using enum from protocol-base.
23
22
  export enum SignalType {
@@ -4,11 +4,11 @@
4
4
  */
5
5
 
6
6
  import { IDisposable } from "@fluidframework/core-interfaces";
7
+ import { ISummaryTree } from "@fluidframework/driver-definitions";
7
8
  import {
8
9
  IDocumentStorageService,
9
10
  ISummaryContext,
10
11
  } from "@fluidframework/driver-definitions/internal";
11
- import { ISummaryTree } from "@fluidframework/protocol-definitions";
12
12
 
13
13
  /**
14
14
  * A storage service wrapper whose sole job is to intercept calls to uploadSummaryWithContext and ensure they include
package/src/quorum.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { IFluidCodeDetails } from "@fluidframework/container-definitions/internal";
7
- import { ICommittedProposal } from "@fluidframework/protocol-definitions";
7
+ import { ICommittedProposal } from "@fluidframework/driver-definitions/internal";
8
8
 
9
9
  export function initQuorumValuesFromCodeDetails(
10
10
  source: IFluidCodeDetails,
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { IDisposable } from "@fluidframework/core-interfaces";
7
7
  import { assert } from "@fluidframework/core-utils/internal";
8
+ import { ISummaryHandle, ISummaryTree } from "@fluidframework/driver-definitions";
8
9
  import {
9
10
  FetchSource,
10
11
  IDocumentStorageService,
@@ -12,15 +13,11 @@ import {
12
13
  ISnapshot,
13
14
  ISnapshotFetchOptions,
14
15
  ISummaryContext,
15
- } from "@fluidframework/driver-definitions/internal";
16
- import { runWithRetry } from "@fluidframework/driver-utils/internal";
17
- import {
18
16
  ICreateBlobResponse,
19
17
  ISnapshotTree,
20
- ISummaryHandle,
21
- ISummaryTree,
22
18
  IVersion,
23
- } from "@fluidframework/protocol-definitions";
19
+ } from "@fluidframework/driver-definitions/internal";
20
+ import { runWithRetry } from "@fluidframework/driver-utils/internal";
24
21
  import {
25
22
  ITelemetryLoggerExt,
26
23
  GenericError,
@@ -3,32 +3,31 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
+ import { stringToBuffer } from "@fluid-internal/client-utils";
6
7
  import {
7
8
  IGetPendingLocalStateProps,
8
9
  IRuntime,
9
10
  } from "@fluidframework/container-definitions/internal";
10
- import { stringToBuffer } from "@fluid-internal/client-utils";
11
+ import type { IEventProvider, IEvent, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
11
12
  import { assert } from "@fluidframework/core-utils/internal";
13
+ import { ISequencedDocumentMessage } from "@fluidframework/driver-definitions";
12
14
  import {
13
15
  FetchSource,
14
16
  IDocumentStorageService,
15
17
  IResolvedUrl,
16
18
  ISnapshot,
17
- } from "@fluidframework/driver-definitions/internal";
18
- import { getSnapshotTree } from "@fluidframework/driver-utils/internal";
19
- import {
20
19
  type IDocumentAttributes,
21
- ISequencedDocumentMessage,
22
20
  ISnapshotTree,
23
21
  IVersion,
24
- } from "@fluidframework/protocol-definitions";
22
+ } from "@fluidframework/driver-definitions/internal";
23
+ import { getSnapshotTree } from "@fluidframework/driver-utils/internal";
25
24
  import {
26
25
  MonitoringContext,
27
26
  PerformanceEvent,
28
27
  UsageError,
29
28
  createChildMonitoringContext,
30
29
  } from "@fluidframework/telemetry-utils/internal";
31
- import type { ITelemetryBaseLogger, IEventProvider, IEvent } from "@fluidframework/core-interfaces";
30
+
32
31
  import { ISerializableBlobContents, getBlobContentsFromTree } from "./containerStorageAdapter.js";
33
32
  import { convertSnapshotToSnapshotInfo, getDocumentAttributes } from "./utils.js";
34
33
 
@@ -93,6 +92,8 @@ export interface IPendingDetachedContainerState extends SnapshotWithBlobs {
93
92
  attached: false;
94
93
  /** Indicates whether we expect the rehydrated container to have non-empty Detached Blob Storage */
95
94
  hasAttachmentBlobs: boolean;
95
+ /** Used by the memory blob storage to persisted attachment blobs */
96
+ attachmentBlobs?: string;
96
97
  /**
97
98
  * Runtime-specific state that will be needed to properly rehydrate
98
99
  * (it's included in ContainerContext passed to instantiateRuntime)
package/src/utils.ts CHANGED
@@ -5,7 +5,12 @@
5
5
 
6
6
  import { Uint8ArrayToString, bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
7
7
  import { assert, compareArrays, unreachableCase } from "@fluidframework/core-utils/internal";
8
- import { DriverErrorTypes } from "@fluidframework/driver-definitions/internal";
8
+ import { ISummaryTree, SummaryType } from "@fluidframework/driver-definitions";
9
+ import {
10
+ DriverErrorTypes,
11
+ IDocumentAttributes,
12
+ ISnapshotTree,
13
+ } from "@fluidframework/driver-definitions/internal";
9
14
  import {
10
15
  IDocumentStorageService,
11
16
  type ISnapshot,
@@ -16,12 +21,6 @@ import {
16
21
  isCombinedAppAndProtocolSummary,
17
22
  readAndParse,
18
23
  } from "@fluidframework/driver-utils/internal";
19
- import {
20
- IDocumentAttributes,
21
- ISnapshotTree,
22
- ISummaryTree,
23
- SummaryType,
24
- } from "@fluidframework/protocol-definitions";
25
24
  import { LoggingError, UsageError } from "@fluidframework/telemetry-utils/internal";
26
25
  import { v4 as uuid } from "uuid";
27
26