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

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 (166) hide show
  1. package/api-report/container-loader.alpha.api.md +59 -4
  2. package/api-report/container-loader.beta.api.md +7 -3
  3. package/api-report/container-loader.public.api.md +7 -3
  4. package/biome.jsonc +4 -0
  5. package/dist/audience.js +2 -1
  6. package/dist/audience.js.map +1 -1
  7. package/dist/catchUpMonitor.js +11 -8
  8. package/dist/catchUpMonitor.js.map +1 -1
  9. package/dist/connectionManager.d.ts +2 -2
  10. package/dist/connectionManager.d.ts.map +1 -1
  11. package/dist/connectionManager.js +91 -63
  12. package/dist/connectionManager.js.map +1 -1
  13. package/dist/connectionStateHandler.js +35 -11
  14. package/dist/connectionStateHandler.js.map +1 -1
  15. package/dist/container.d.ts +3 -2
  16. package/dist/container.d.ts.map +1 -1
  17. package/dist/container.js +162 -126
  18. package/dist/container.js.map +1 -1
  19. package/dist/containerContext.d.ts +2 -2
  20. package/dist/containerContext.d.ts.map +1 -1
  21. package/dist/containerContext.js +34 -8
  22. package/dist/containerContext.js.map +1 -1
  23. package/dist/containerStorageAdapter.js +17 -9
  24. package/dist/containerStorageAdapter.js.map +1 -1
  25. package/dist/contracts.d.ts +2 -2
  26. package/dist/contracts.d.ts.map +1 -1
  27. package/dist/contracts.js.map +1 -1
  28. package/dist/debugLogger.js +2 -0
  29. package/dist/debugLogger.js.map +1 -1
  30. package/dist/deltaManager.d.ts +2 -2
  31. package/dist/deltaManager.d.ts.map +1 -1
  32. package/dist/deltaManager.js +48 -35
  33. package/dist/deltaManager.js.map +1 -1
  34. package/dist/deltaQueue.js +14 -7
  35. package/dist/deltaQueue.js.map +1 -1
  36. package/dist/error.js +5 -4
  37. package/dist/error.js.map +1 -1
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/legacy.d.ts +5 -0
  42. package/dist/loader.js +5 -1
  43. package/dist/loader.js.map +1 -1
  44. package/dist/noopHeuristic.d.ts +1 -1
  45. package/dist/noopHeuristic.d.ts.map +1 -1
  46. package/dist/noopHeuristic.js +3 -1
  47. package/dist/noopHeuristic.js.map +1 -1
  48. package/dist/packageVersion.d.ts +1 -1
  49. package/dist/packageVersion.js +1 -1
  50. package/dist/packageVersion.js.map +1 -1
  51. package/dist/protocol/index.d.ts +7 -0
  52. package/dist/protocol/index.d.ts.map +1 -0
  53. package/dist/protocol/index.js +12 -0
  54. package/dist/protocol/index.js.map +1 -0
  55. package/dist/protocol/protocol.d.ts +52 -0
  56. package/dist/protocol/protocol.d.ts.map +1 -0
  57. package/dist/protocol/protocol.js +115 -0
  58. package/dist/protocol/protocol.js.map +1 -0
  59. package/dist/protocol/quorum.d.ts +185 -0
  60. package/dist/protocol/quorum.d.ts.map +1 -0
  61. package/dist/protocol/quorum.js +440 -0
  62. package/dist/protocol/quorum.js.map +1 -0
  63. package/dist/protocol.d.ts +2 -3
  64. package/dist/protocol.d.ts.map +1 -1
  65. package/dist/protocol.js +4 -2
  66. package/dist/protocol.js.map +1 -1
  67. package/dist/protocolTreeDocumentStorageService.d.ts +7 -7
  68. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  69. package/dist/protocolTreeDocumentStorageService.js +16 -7
  70. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  71. package/dist/retriableDocumentStorageService.js +4 -1
  72. package/dist/retriableDocumentStorageService.js.map +1 -1
  73. package/dist/serializedStateManager.d.ts +5 -3
  74. package/dist/serializedStateManager.d.ts.map +1 -1
  75. package/dist/serializedStateManager.js +26 -5
  76. package/dist/serializedStateManager.js.map +1 -1
  77. package/lib/audience.js +2 -1
  78. package/lib/audience.js.map +1 -1
  79. package/lib/catchUpMonitor.js +11 -8
  80. package/lib/catchUpMonitor.js.map +1 -1
  81. package/lib/connectionManager.d.ts +2 -2
  82. package/lib/connectionManager.d.ts.map +1 -1
  83. package/lib/connectionManager.js +91 -63
  84. package/lib/connectionManager.js.map +1 -1
  85. package/lib/connectionStateHandler.js +35 -11
  86. package/lib/connectionStateHandler.js.map +1 -1
  87. package/lib/container.d.ts +3 -2
  88. package/lib/container.d.ts.map +1 -1
  89. package/lib/container.js +162 -126
  90. package/lib/container.js.map +1 -1
  91. package/lib/containerContext.d.ts +2 -2
  92. package/lib/containerContext.d.ts.map +1 -1
  93. package/lib/containerContext.js +34 -8
  94. package/lib/containerContext.js.map +1 -1
  95. package/lib/containerStorageAdapter.js +17 -9
  96. package/lib/containerStorageAdapter.js.map +1 -1
  97. package/lib/contracts.d.ts +2 -2
  98. package/lib/contracts.d.ts.map +1 -1
  99. package/lib/contracts.js.map +1 -1
  100. package/lib/debugLogger.js +2 -0
  101. package/lib/debugLogger.js.map +1 -1
  102. package/lib/deltaManager.d.ts +2 -2
  103. package/lib/deltaManager.d.ts.map +1 -1
  104. package/lib/deltaManager.js +48 -35
  105. package/lib/deltaManager.js.map +1 -1
  106. package/lib/deltaQueue.js +14 -7
  107. package/lib/deltaQueue.js.map +1 -1
  108. package/lib/error.js +5 -4
  109. package/lib/error.js.map +1 -1
  110. package/lib/index.d.ts +1 -0
  111. package/lib/index.d.ts.map +1 -1
  112. package/lib/index.js.map +1 -1
  113. package/lib/legacy.d.ts +5 -0
  114. package/lib/loader.js +5 -1
  115. package/lib/loader.js.map +1 -1
  116. package/lib/noopHeuristic.d.ts +1 -1
  117. package/lib/noopHeuristic.d.ts.map +1 -1
  118. package/lib/noopHeuristic.js +3 -1
  119. package/lib/noopHeuristic.js.map +1 -1
  120. package/lib/packageVersion.d.ts +1 -1
  121. package/lib/packageVersion.js +1 -1
  122. package/lib/packageVersion.js.map +1 -1
  123. package/lib/protocol/index.d.ts +7 -0
  124. package/lib/protocol/index.d.ts.map +1 -0
  125. package/lib/protocol/index.js +7 -0
  126. package/lib/protocol/index.js.map +1 -0
  127. package/lib/protocol/protocol.d.ts +52 -0
  128. package/lib/protocol/protocol.d.ts.map +1 -0
  129. package/lib/protocol/protocol.js +111 -0
  130. package/lib/protocol/protocol.js.map +1 -0
  131. package/lib/protocol/quorum.d.ts +185 -0
  132. package/lib/protocol/quorum.d.ts.map +1 -0
  133. package/lib/protocol/quorum.js +431 -0
  134. package/lib/protocol/quorum.js.map +1 -0
  135. package/lib/protocol.d.ts +2 -3
  136. package/lib/protocol.d.ts.map +1 -1
  137. package/lib/protocol.js +3 -1
  138. package/lib/protocol.js.map +1 -1
  139. package/lib/protocolTreeDocumentStorageService.d.ts +7 -7
  140. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  141. package/lib/protocolTreeDocumentStorageService.js +16 -7
  142. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  143. package/lib/retriableDocumentStorageService.js +4 -1
  144. package/lib/retriableDocumentStorageService.js.map +1 -1
  145. package/lib/serializedStateManager.d.ts +5 -3
  146. package/lib/serializedStateManager.d.ts.map +1 -1
  147. package/lib/serializedStateManager.js +26 -5
  148. package/lib/serializedStateManager.js.map +1 -1
  149. package/package.json +19 -14
  150. package/src/catchUpMonitor.ts +1 -1
  151. package/src/connectionManager.ts +3 -7
  152. package/src/container.ts +16 -9
  153. package/src/containerContext.ts +2 -5
  154. package/src/contracts.ts +3 -6
  155. package/src/deltaManager.ts +3 -5
  156. package/src/index.ts +7 -0
  157. package/src/noopHeuristic.ts +1 -1
  158. package/src/packageVersion.ts +1 -1
  159. package/src/protocol/README.md +10 -0
  160. package/src/protocol/index.ts +16 -0
  161. package/src/protocol/protocol.ts +185 -0
  162. package/src/protocol/quorum.ts +584 -0
  163. package/src/protocol.ts +4 -6
  164. package/src/protocolTreeDocumentStorageService.ts +16 -8
  165. package/src/serializedStateManager.ts +25 -4
  166. package/tsconfig.json +2 -0
package/dist/container.js CHANGED
@@ -197,6 +197,41 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
197
197
  return container;
198
198
  }, { start: true, end: true, cancel: "generic" });
199
199
  }
200
+ // Tells if container can reconnect on losing fist connection
201
+ // If false, container gets closed on loss of connection.
202
+ _canReconnect;
203
+ clientDetailsOverride;
204
+ urlResolver;
205
+ serviceFactory;
206
+ codeLoader;
207
+ options;
208
+ scope;
209
+ subLogger;
210
+ // eslint-disable-next-line import/no-deprecated
211
+ detachedBlobStorage;
212
+ protocolHandlerBuilder;
213
+ client;
214
+ mc;
215
+ /**
216
+ * Used by the RelativeLoader to spawn a new Container for the same document. Used to create the summarizing client.
217
+ */
218
+ clone;
219
+ /**
220
+ * Lifecycle state of the container, used mainly to prevent re-entrancy and telemetry
221
+ *
222
+ * States are allowed to progress to further states:
223
+ * "loading" - "loaded" - "closing" - "disposing" - "closed" - "disposed"
224
+ *
225
+ * For example, moving from "closed" to "disposing" is not allowed since it is an earlier state.
226
+ *
227
+ * loading: Container has been created, but is not yet in normal/loaded state
228
+ * loaded: Container is in normal/loaded state
229
+ * closing: Container has started closing process (for re-entrancy prevention)
230
+ * disposing: Container has started disposing process (for re-entrancy prevention)
231
+ * closed: Container has closed
232
+ * disposed: Container has been disposed
233
+ */
234
+ _lifecycleState = "loading";
200
235
  setLoaded() {
201
236
  // It's conceivable the container could be closed when this is called
202
237
  // Only transition states if currently loading
@@ -239,18 +274,39 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
239
274
  get disposed() {
240
275
  return this._lifecycleState === "disposing" || this._lifecycleState === "disposed";
241
276
  }
277
+ storageAdapter;
278
+ _deltaManager;
279
+ service;
280
+ _runtime;
242
281
  get runtime() {
243
282
  if (this._runtime === undefined) {
244
283
  throw new Error("Attempted to access runtime before it was defined");
245
284
  }
246
285
  return this._runtime;
247
286
  }
287
+ _protocolHandler;
248
288
  get protocolHandler() {
249
289
  if (this._protocolHandler === undefined) {
250
290
  throw new Error("Attempted to access protocolHandler before it was defined");
251
291
  }
252
292
  return this._protocolHandler;
253
293
  }
294
+ /** During initialization we pause the inbound queues. We track this state to ensure we only call resume once */
295
+ inboundQueuePausedFromInit = true;
296
+ firstConnection = true;
297
+ connectionTransitionTimes = [];
298
+ _loadedFromVersion;
299
+ _dirtyContainer = false;
300
+ attachmentData = { state: container_definitions_1.AttachState.Detached };
301
+ serializedStateManager;
302
+ _containerId;
303
+ lastVisible;
304
+ visibilityEventHandler;
305
+ connectionStateHandler;
306
+ clientsWhoShouldHaveLeft = new Set();
307
+ _containerMetadata = {};
308
+ setAutoReconnectTime = client_utils_1.performance.now();
309
+ noopHeuristic;
254
310
  get connectionMode() {
255
311
  return this._deltaManager.connectionManager.connectionMode;
256
312
  }
@@ -314,6 +370,11 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
314
370
  get isInteractiveClient() {
315
371
  return this.deltaManager.clientDetails.capabilities.interactive;
316
372
  }
373
+ get supportGetSnapshotApi() {
374
+ const supportGetSnapshotApi = this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch2") ===
375
+ true && this.service?.policies?.supportGetSnapshotApi === true;
376
+ return supportGetSnapshotApi;
377
+ }
317
378
  /**
318
379
  * Get the code details that are currently specified for the container.
319
380
  * @returns The current code details if any are specified, undefined if none are specified.
@@ -321,6 +382,7 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
321
382
  getSpecifiedCodeDetails() {
322
383
  return this.getCodeDetailsFromQuorum();
323
384
  }
385
+ _loadedCodeDetails;
324
386
  /**
325
387
  * Get the code details that were used to load the container.
326
388
  * @returns The code details that were used to load the container if it is loaded, undefined if it is not yet
@@ -329,6 +391,7 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
329
391
  getLoadedCodeDetails() {
330
392
  return this._loadedCodeDetails;
331
393
  }
394
+ _loadedModule;
332
395
  /**
333
396
  * Retrieves the audience associated with the document
334
397
  */
@@ -367,6 +430,7 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
367
430
  this._lifecycleEvents.once("disposed", disposedHandler);
368
431
  });
369
432
  }
433
+ _lifecycleEvents = new client_utils_1.TypedEventEmitter();
370
434
  constructor(createProps, loadProps) {
371
435
  super((name, error) => {
372
436
  this.mc.logger.sendErrorEvent({
@@ -375,128 +439,6 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
375
439
  }, error);
376
440
  this.close((0, internal_5.normalizeError)(error));
377
441
  });
378
- /**
379
- * Lifecycle state of the container, used mainly to prevent re-entrancy and telemetry
380
- *
381
- * States are allowed to progress to further states:
382
- * "loading" - "loaded" - "closing" - "disposing" - "closed" - "disposed"
383
- *
384
- * For example, moving from "closed" to "disposing" is not allowed since it is an earlier state.
385
- *
386
- * loading: Container has been created, but is not yet in normal/loaded state
387
- * loaded: Container is in normal/loaded state
388
- * closing: Container has started closing process (for re-entrancy prevention)
389
- * disposing: Container has started disposing process (for re-entrancy prevention)
390
- * closed: Container has closed
391
- * disposed: Container has been disposed
392
- */
393
- this._lifecycleState = "loading";
394
- /** During initialization we pause the inbound queues. We track this state to ensure we only call resume once */
395
- this.inboundQueuePausedFromInit = true;
396
- this.firstConnection = true;
397
- this.connectionTransitionTimes = [];
398
- this._dirtyContainer = false;
399
- this.attachmentData = { state: container_definitions_1.AttachState.Detached };
400
- this.clientsWhoShouldHaveLeft = new Set();
401
- this._containerMetadata = {};
402
- this.setAutoReconnectTime = client_utils_1.performance.now();
403
- this._lifecycleEvents = new client_utils_1.TypedEventEmitter();
404
- this._disposed = false;
405
- this.attach = (0, utils_js_1.runSingle)(async (request, attachProps) => {
406
- await internal_5.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
407
- if (this._lifecycleState !== "loaded" ||
408
- this.attachmentData.state === container_definitions_1.AttachState.Attached) {
409
- // pre-0.58 error message: containerNotValidForAttach
410
- throw new internal_5.UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}] and [${this.attachState}]`);
411
- }
412
- const normalizeErrorAndClose = (error) => {
413
- const newError = (0, internal_5.normalizeError)(error);
414
- this.close(newError);
415
- // add resolved URL on error object so that host has the ability to find this document and delete it
416
- newError.addTelemetryProperties({
417
- resolvedUrl: this.service?.resolvedUrl?.url,
418
- });
419
- return newError;
420
- };
421
- const setAttachmentData = (attachmentData) => {
422
- const previousState = this.attachmentData.state;
423
- this.attachmentData = attachmentData;
424
- const state = this.attachmentData.state;
425
- if (state !== previousState && state !== container_definitions_1.AttachState.Detached) {
426
- try {
427
- this.runtime.setAttachState(state);
428
- this.emit(state.toLocaleLowerCase());
429
- }
430
- catch (error) {
431
- throw normalizeErrorAndClose(error);
432
- }
433
- }
434
- };
435
- const createAttachmentSummary = (redirectTable) => {
436
- try {
437
- (0, internal_2.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
438
- return (0, utils_js_1.combineAppAndProtocolSummary)(this.runtime.createSummary(redirectTable), this.captureProtocolSummary());
439
- }
440
- catch (error) {
441
- throw normalizeErrorAndClose(error);
442
- }
443
- };
444
- const createOrGetStorageService = async (summary) => {
445
- // Actually go and create the resolved document
446
- if (this.service === undefined) {
447
- const createNewResolvedUrl = await this.urlResolver.resolve(request);
448
- (0, internal_2.assert)(this.client.details.type !== summarizerClientType &&
449
- createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
450
- this.service = await (0, internal_4.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
451
- cancel: this._deltaManager.closeAbortController.signal,
452
- });
453
- }
454
- this.storageAdapter.connectToService(this.service);
455
- return this.storageAdapter;
456
- };
457
- let attachP = (0, attachment_js_1.runRetriableAttachProcess)({
458
- initialAttachmentData: this.attachmentData,
459
- offlineLoadEnabled: this.serializedStateManager.offlineLoadEnabled,
460
- detachedBlobStorage: this.detachedBlobStorage,
461
- setAttachmentData,
462
- createAttachmentSummary,
463
- createOrGetStorageService,
464
- });
465
- // only enable the new behavior if the config is set
466
- if (this.mc.config.getBoolean("Fluid.Container.RetryOnAttachFailure") !== true) {
467
- attachP = attachP.catch((error) => {
468
- throw normalizeErrorAndClose(error);
469
- });
470
- }
471
- // If offline load is enabled, attachP will return the attach summary (in Snapshot format) so we can initialize SerializedStateManager
472
- const snapshotWithBlobs = await attachP;
473
- this.serializedStateManager.setInitialSnapshot(snapshotWithBlobs);
474
- if (!this.closed) {
475
- this.detachedBlobStorage.dispose?.();
476
- this.handleDeltaConnectionArg(attachProps?.deltaConnection, {
477
- fetchOpsFromStorage: false,
478
- reason: { text: "createDetached" },
479
- });
480
- }
481
- }, { start: true, end: true, cancel: "generic" });
482
- });
483
- this.getAbsoluteUrl = async (relativeUrl) => {
484
- if (this.resolvedUrl === undefined) {
485
- return undefined;
486
- }
487
- return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0, contracts_js_1.getPackageName)(this._loadedCodeDetails));
488
- };
489
- this.metadataUpdateHandler = (metadata) => {
490
- this._containerMetadata = { ...this._containerMetadata, ...metadata };
491
- this.emit("metadataUpdate", metadata);
492
- };
493
- this.updateDirtyContainerState = (dirty) => {
494
- if (this._dirtyContainer === dirty) {
495
- return;
496
- }
497
- this._dirtyContainer = dirty;
498
- this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
499
- };
500
442
  const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
501
443
  this.connectionTransitionTimes[connectionState_js_1.ConnectionState.Disconnected] = client_utils_1.performance.now();
502
444
  const pendingLocalState = loadProps?.pendingLocalState;
@@ -641,7 +583,7 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
641
583
  const offlineLoadEnabled = (this.isInteractiveClient &&
642
584
  this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) ??
643
585
  options.enableOfflineLoad === true;
644
- this.serializedStateManager = new serializedStateManager_js_1.SerializedStateManager(pendingLocalState, this.subLogger, this.storageAdapter, offlineLoadEnabled, this, () => this.isDirty);
586
+ this.serializedStateManager = new serializedStateManager_js_1.SerializedStateManager(pendingLocalState, this.subLogger, this.storageAdapter, offlineLoadEnabled, this, () => this._deltaManager.connectionManager.shouldJoinWrite());
645
587
  const isDomAvailable = typeof document === "object" &&
646
588
  document !== null &&
647
589
  typeof document.addEventListener === "function" &&
@@ -724,6 +666,7 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
724
666
  }
725
667
  }
726
668
  }
669
+ _disposed = false;
727
670
  disposeCore(error) {
728
671
  (0, internal_2.assert)(!this._disposed, 0x54c /* Container already disposed */);
729
672
  this._disposed = true;
@@ -822,6 +765,84 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
822
765
  };
823
766
  return JSON.stringify(detachedContainerState);
824
767
  }
768
+ attach = (0, utils_js_1.runSingle)(async (request, attachProps) => {
769
+ await internal_5.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
770
+ if (this._lifecycleState !== "loaded" ||
771
+ this.attachmentData.state === container_definitions_1.AttachState.Attached) {
772
+ // pre-0.58 error message: containerNotValidForAttach
773
+ throw new internal_5.UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}] and [${this.attachState}]`);
774
+ }
775
+ const normalizeErrorAndClose = (error) => {
776
+ const newError = (0, internal_5.normalizeError)(error);
777
+ this.close(newError);
778
+ // add resolved URL on error object so that host has the ability to find this document and delete it
779
+ newError.addTelemetryProperties({
780
+ resolvedUrl: this.service?.resolvedUrl?.url,
781
+ });
782
+ return newError;
783
+ };
784
+ const setAttachmentData = (attachmentData) => {
785
+ const previousState = this.attachmentData.state;
786
+ this.attachmentData = attachmentData;
787
+ const state = this.attachmentData.state;
788
+ if (state !== previousState && state !== container_definitions_1.AttachState.Detached) {
789
+ try {
790
+ this.runtime.setAttachState(state);
791
+ this.emit(state.toLocaleLowerCase());
792
+ }
793
+ catch (error) {
794
+ throw normalizeErrorAndClose(error);
795
+ }
796
+ }
797
+ };
798
+ const createAttachmentSummary = (redirectTable) => {
799
+ try {
800
+ (0, internal_2.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
801
+ return (0, utils_js_1.combineAppAndProtocolSummary)(this.runtime.createSummary(redirectTable), this.captureProtocolSummary());
802
+ }
803
+ catch (error) {
804
+ throw normalizeErrorAndClose(error);
805
+ }
806
+ };
807
+ const createOrGetStorageService = async (summary) => {
808
+ // Actually go and create the resolved document
809
+ if (this.service === undefined) {
810
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
811
+ (0, internal_2.assert)(this.client.details.type !== summarizerClientType &&
812
+ createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
813
+ this.service = await (0, internal_4.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
814
+ cancel: this._deltaManager.closeAbortController.signal,
815
+ });
816
+ }
817
+ this.storageAdapter.connectToService(this.service);
818
+ return this.storageAdapter;
819
+ };
820
+ let attachP = (0, attachment_js_1.runRetriableAttachProcess)({
821
+ initialAttachmentData: this.attachmentData,
822
+ offlineLoadEnabled: this.serializedStateManager.offlineLoadEnabled,
823
+ detachedBlobStorage: this.detachedBlobStorage,
824
+ setAttachmentData,
825
+ createAttachmentSummary,
826
+ createOrGetStorageService,
827
+ });
828
+ // only enable the new behavior if the config is set
829
+ if (this.mc.config.getBoolean("Fluid.Container.RetryOnAttachFailure") !== true) {
830
+ attachP = attachP.catch((error) => {
831
+ throw normalizeErrorAndClose(error);
832
+ });
833
+ }
834
+ // If offline load is enabled, attachP will return the attach summary (in Snapshot format) so we can initialize SerializedStateManager
835
+ const snapshotWithBlobs = await attachP;
836
+ this.serializedStateManager.setInitialSnapshot(snapshotWithBlobs, this.supportGetSnapshotApi);
837
+ if (!this.closed) {
838
+ this.detachedBlobStorage.dispose?.();
839
+ this.handleDeltaConnectionArg(attachProps?.deltaConnection, {
840
+ fetchOpsFromStorage: false,
841
+ reason: { text: "createDetached" },
842
+ });
843
+ }
844
+ }, { start: true, end: true, cancel: "generic" });
845
+ });
825
846
  setAutoReconnectInternal(mode, reason) {
826
847
  const currentMode = this._deltaManager.connectionManager.reconnectMode;
827
848
  if (currentMode === mode) {
@@ -894,6 +915,12 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
894
915
  // Ensure connection to web socket
895
916
  this.connectToDeltaStream(args);
896
917
  }
918
+ getAbsoluteUrl = async (relativeUrl) => {
919
+ if (this.resolvedUrl === undefined) {
920
+ return undefined;
921
+ }
922
+ return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0, contracts_js_1.getPackageName)(this._loadedCodeDetails));
923
+ };
897
924
  async proposeCodeDetails(codeDetails) {
898
925
  if (!(0, internal_1.isFluidCodeDetails)(codeDetails)) {
899
926
  throw new Error("Provided codeDetails are not IFluidCodeDetails");
@@ -962,6 +989,10 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
962
989
  }
963
990
  this._deltaManager.connect(args);
964
991
  }
992
+ metadataUpdateHandler = (metadata) => {
993
+ this._containerMetadata = { ...this._containerMetadata, ...metadata };
994
+ this.emit("metadataUpdate", metadata);
995
+ };
965
996
  async createDocumentService(serviceProvider) {
966
997
  const service = await serviceProvider();
967
998
  // Back-compat for Old driver
@@ -998,10 +1029,8 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
998
1029
  state: container_definitions_1.AttachState.Attached,
999
1030
  };
1000
1031
  timings.phase2 = client_utils_1.performance.now();
1001
- const supportGetSnapshotApi = this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch") ===
1002
- true && this.service?.policies?.supportGetSnapshotApi === true;
1003
1032
  // Fetch specified snapshot.
1004
- const { baseSnapshot, version } = await this.serializedStateManager.fetchSnapshot(specifiedVersion, supportGetSnapshotApi);
1033
+ const { baseSnapshot, version } = await this.serializedStateManager.fetchSnapshot(specifiedVersion, this.supportGetSnapshotApi);
1005
1034
  const baseSnapshotTree = (0, internal_4.getSnapshotTree)(baseSnapshot);
1006
1035
  this._loadedFromVersion = version;
1007
1036
  const attributes = await (0, utils_js_1.getDocumentAttributes)(this.storageAdapter, baseSnapshotTree);
@@ -1507,6 +1536,13 @@ class Container extends internal_5.EventEmitterWithErrorHandling {
1507
1536
  this._lifecycleEvents.emit("runtimeInstantiated");
1508
1537
  this._loadedCodeDetails = codeDetails;
1509
1538
  }
1539
+ updateDirtyContainerState = (dirty) => {
1540
+ if (this._dirtyContainer === dirty) {
1541
+ return;
1542
+ }
1543
+ this._dirtyContainer = dirty;
1544
+ this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
1545
+ };
1510
1546
  /**
1511
1547
  * Set the connected state of the ContainerContext
1512
1548
  * This controls the "connected" state of the ContainerRuntime as well