@fluidframework/container-loader 2.0.0-internal.4.3.0 → 2.0.0-internal.5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +6 -3
  3. package/dist/connectionManager.d.ts +5 -3
  4. package/dist/connectionManager.d.ts.map +1 -1
  5. package/dist/connectionManager.js +19 -15
  6. package/dist/connectionManager.js.map +1 -1
  7. package/dist/connectionStateHandler.d.ts +11 -9
  8. package/dist/connectionStateHandler.d.ts.map +1 -1
  9. package/dist/connectionStateHandler.js +11 -11
  10. package/dist/connectionStateHandler.js.map +1 -1
  11. package/dist/container.d.ts +62 -36
  12. package/dist/container.d.ts.map +1 -1
  13. package/dist/container.js +71 -89
  14. package/dist/container.js.map +1 -1
  15. package/dist/containerContext.d.ts +2 -2
  16. package/dist/containerContext.d.ts.map +1 -1
  17. package/dist/containerContext.js +3 -7
  18. package/dist/containerContext.js.map +1 -1
  19. package/dist/containerStorageAdapter.d.ts +3 -3
  20. package/dist/containerStorageAdapter.d.ts.map +1 -1
  21. package/dist/containerStorageAdapter.js.map +1 -1
  22. package/dist/contracts.d.ts +3 -3
  23. package/dist/contracts.d.ts.map +1 -1
  24. package/dist/contracts.js.map +1 -1
  25. package/dist/deltaManager.d.ts +3 -2
  26. package/dist/deltaManager.d.ts.map +1 -1
  27. package/dist/deltaManager.js +4 -5
  28. package/dist/deltaManager.js.map +1 -1
  29. package/dist/index.d.ts +1 -2
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/loader.d.ts +9 -5
  33. package/dist/loader.d.ts.map +1 -1
  34. package/dist/loader.js +28 -34
  35. package/dist/loader.js.map +1 -1
  36. package/dist/packageVersion.d.ts +1 -1
  37. package/dist/packageVersion.js +1 -1
  38. package/dist/packageVersion.js.map +1 -1
  39. package/dist/retriableDocumentStorageService.d.ts +3 -2
  40. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  41. package/dist/retriableDocumentStorageService.js.map +1 -1
  42. package/lib/connectionManager.d.ts +5 -3
  43. package/lib/connectionManager.d.ts.map +1 -1
  44. package/lib/connectionManager.js +20 -16
  45. package/lib/connectionManager.js.map +1 -1
  46. package/lib/connectionStateHandler.d.ts +11 -9
  47. package/lib/connectionStateHandler.d.ts.map +1 -1
  48. package/lib/connectionStateHandler.js +12 -12
  49. package/lib/connectionStateHandler.js.map +1 -1
  50. package/lib/container.d.ts +62 -36
  51. package/lib/container.d.ts.map +1 -1
  52. package/lib/container.js +72 -90
  53. package/lib/container.js.map +1 -1
  54. package/lib/containerContext.d.ts +2 -2
  55. package/lib/containerContext.d.ts.map +1 -1
  56. package/lib/containerContext.js +3 -7
  57. package/lib/containerContext.js.map +1 -1
  58. package/lib/containerStorageAdapter.d.ts +3 -3
  59. package/lib/containerStorageAdapter.d.ts.map +1 -1
  60. package/lib/containerStorageAdapter.js.map +1 -1
  61. package/lib/contracts.d.ts +3 -3
  62. package/lib/contracts.d.ts.map +1 -1
  63. package/lib/contracts.js.map +1 -1
  64. package/lib/deltaManager.d.ts +3 -2
  65. package/lib/deltaManager.d.ts.map +1 -1
  66. package/lib/deltaManager.js +5 -6
  67. package/lib/deltaManager.js.map +1 -1
  68. package/lib/index.d.ts +1 -2
  69. package/lib/index.d.ts.map +1 -1
  70. package/lib/index.js +1 -1
  71. package/lib/index.js.map +1 -1
  72. package/lib/loader.d.ts +9 -5
  73. package/lib/loader.d.ts.map +1 -1
  74. package/lib/loader.js +28 -34
  75. package/lib/loader.js.map +1 -1
  76. package/lib/packageVersion.d.ts +1 -1
  77. package/lib/packageVersion.js +1 -1
  78. package/lib/packageVersion.js.map +1 -1
  79. package/lib/retriableDocumentStorageService.d.ts +3 -2
  80. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  81. package/lib/retriableDocumentStorageService.js.map +1 -1
  82. package/package.json +27 -10
  83. package/src/connectionManager.ts +29 -20
  84. package/src/connectionStateHandler.ts +26 -17
  85. package/src/container.ts +169 -147
  86. package/src/containerContext.ts +3 -9
  87. package/src/containerStorageAdapter.ts +4 -4
  88. package/src/contracts.ts +3 -3
  89. package/src/deltaManager.ts +13 -8
  90. package/src/index.ts +1 -8
  91. package/src/loader.ts +56 -47
  92. package/src/packageVersion.ts +1 -1
  93. package/src/retriableDocumentStorageService.ts +3 -2
package/src/container.ts CHANGED
@@ -7,11 +7,7 @@
7
7
  import merge from "lodash/merge";
8
8
 
9
9
  import { v4 as uuid } from "uuid";
10
- import {
11
- ITelemetryLogger,
12
- ITelemetryProperties,
13
- TelemetryEventCategory,
14
- } from "@fluidframework/common-definitions";
10
+ import { ITelemetryProperties, TelemetryEventCategory } from "@fluidframework/common-definitions";
15
11
  import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
16
12
  import { IRequest, IResponse, IFluidRouter, FluidObject } from "@fluidframework/core-interfaces";
17
13
  import {
@@ -29,22 +25,24 @@ import {
29
25
  IFluidCodeDetails,
30
26
  isFluidCodeDetails,
31
27
  IBatchMessage,
28
+ ICodeDetailsLoader,
29
+ IHostLoader,
32
30
  } from "@fluidframework/container-definitions";
33
31
  import { GenericError, UsageError } from "@fluidframework/container-utils";
34
32
  import {
33
+ IAnyDriverError,
35
34
  IDocumentService,
35
+ IDocumentServiceFactory,
36
36
  IDocumentStorageService,
37
- IFluidResolvedUrl,
38
37
  IResolvedUrl,
38
+ IUrlResolver,
39
39
  } from "@fluidframework/driver-definitions";
40
40
  import {
41
41
  readAndParse,
42
42
  OnlineStatus,
43
43
  isOnline,
44
- ensureFluidResolvedUrl,
45
44
  combineAppAndProtocolSummary,
46
45
  runWithRetry,
47
- isFluidResolvedUrl,
48
46
  isCombinedAppAndProtocolSummary,
49
47
  } from "@fluidframework/driver-utils";
50
48
  import { IQuorumSnapshot } from "@fluidframework/protocol-base";
@@ -79,13 +77,14 @@ import {
79
77
  MonitoringContext,
80
78
  loggerToMonitoringContext,
81
79
  wrapError,
80
+ ITelemetryLoggerExt,
82
81
  } from "@fluidframework/telemetry-utils";
83
82
  import { Audience } from "./audience";
84
83
  import { ContainerContext } from "./containerContext";
85
84
  import { ReconnectMode, IConnectionManagerFactoryArgs, getPackageName } from "./contracts";
86
85
  import { DeltaManager, IConnectionArgs } from "./deltaManager";
87
86
  import { DeltaManagerProxy } from "./deltaManagerProxy";
88
- import { ILoaderOptions, Loader, RelativeLoader } from "./loader";
87
+ import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader";
89
88
  import { pkgVersion } from "./packageVersion";
90
89
  import {
91
90
  ContainerStorageAdapter,
@@ -116,44 +115,82 @@ const dirtyContainerEvent = "dirty";
116
115
  const savedContainerEvent = "saved";
117
116
 
118
117
  /**
119
- * @deprecated this is an internal interface and will not longer be exported in future versions
120
118
  * @internal
121
119
  */
122
- export interface IContainerLoadOptions {
123
- /**
124
- * Disables the Container from reconnecting if false, allows reconnect otherwise.
125
- */
126
- canReconnect?: boolean;
120
+ export interface IContainerLoadProps {
127
121
  /**
128
- * Client details provided in the override will be merged over the default client.
122
+ * The resolved url of the container being loaded
129
123
  */
130
- clientDetailsOverride?: IClientDetails;
131
- resolvedUrl: IFluidResolvedUrl;
124
+ readonly resolvedUrl: IResolvedUrl;
132
125
  /**
133
126
  * Control which snapshot version to load from. See IParsedUrl for detailed information.
134
127
  */
135
- version: string | undefined;
128
+ readonly version: string | undefined;
136
129
  /**
137
130
  * Loads the Container in paused state if true, unpaused otherwise.
138
131
  */
139
- loadMode?: IContainerLoadMode;
132
+ readonly loadMode?: IContainerLoadMode;
133
+
134
+ /**
135
+ * The pending state serialized from a pervious container instance
136
+ */
137
+ readonly pendingLocalState?: IPendingContainerState;
140
138
  }
141
139
 
142
140
  /**
143
- * @deprecated this is an internal interface and will not longer be exported in future versions
144
141
  * @internal
145
142
  */
146
- export interface IContainerConfig {
147
- resolvedUrl?: IFluidResolvedUrl;
148
- canReconnect?: boolean;
143
+ export interface IContainerCreateProps {
144
+ /**
145
+ * Disables the Container from reconnecting if false, allows reconnect otherwise.
146
+ */
147
+ readonly canReconnect?: boolean;
149
148
  /**
150
149
  * Client details provided in the override will be merged over the default client.
151
150
  */
152
- clientDetailsOverride?: IClientDetails;
151
+ readonly clientDetailsOverride?: IClientDetails;
152
+
153
+ /**
154
+ * The url resolver used by the loader for resolving external urls
155
+ * into Fluid urls such that the container specified by the
156
+ * external url can be loaded.
157
+ */
158
+ readonly urlResolver: IUrlResolver;
159
+ /**
160
+ * The document service factory take the Fluid url provided
161
+ * by the resolved url and constructs all the necessary services
162
+ * for communication with the container's server.
163
+ */
164
+ readonly documentServiceFactory: IDocumentServiceFactory;
153
165
  /**
154
- * Serialized state from a previous instance of this container
166
+ * The code loader handles loading the necessary code
167
+ * for running a container once it is loaded.
155
168
  */
156
- serializedContainerState?: IPendingContainerState;
169
+ readonly codeLoader: ICodeDetailsLoader;
170
+
171
+ /**
172
+ * A property bag of options used by various layers
173
+ * to control features
174
+ */
175
+ readonly options: ILoaderOptions;
176
+
177
+ /**
178
+ * Scope is provided to all container and is a set of shared
179
+ * services for container's to integrate with their host environment.
180
+ */
181
+ readonly scope: FluidObject;
182
+
183
+ /**
184
+ * The logger downstream consumers should construct their loggers from
185
+ */
186
+ readonly subLogger: ITelemetryLoggerExt;
187
+
188
+ /**
189
+ * Blobs storage for detached containers.
190
+ */
191
+ readonly detachedBlobStorage?: IDetachedBlobStorage;
192
+
193
+ readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
157
194
  }
158
195
 
159
196
  /**
@@ -259,7 +296,7 @@ const getCodeProposal =
259
296
  * @param action - functor to call and measure
260
297
  */
261
298
  export async function ReportIfTooLong(
262
- logger: ITelemetryLogger,
299
+ logger: ITelemetryLoggerExt,
263
300
  eventName: string,
264
301
  action: () => Promise<ITelemetryProperties>,
265
302
  ) {
@@ -273,7 +310,6 @@ export async function ReportIfTooLong(
273
310
  /**
274
311
  * State saved by a container at close time, to be used to load a new instance
275
312
  * of the container to the same state
276
- * @deprecated this is an internal interface and will not longer be exported in future versions
277
313
  * @internal
278
314
  */
279
315
  export interface IPendingContainerState {
@@ -300,49 +336,46 @@ export interface IPendingContainerState {
300
336
 
301
337
  const summarizerClientType = "summarizer";
302
338
 
303
- /**
304
- * @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
305
- */
306
339
  export class Container
307
340
  extends EventEmitterWithErrorHandling<IContainerEvents>
308
341
  implements IContainer, IContainerExperimental
309
342
  {
310
343
  public static version = "^0.1.0";
311
344
 
345
+ public static async clone(
346
+ container: Container,
347
+ loadProps: IContainerLoadProps,
348
+ createParamOverrides: Partial<IContainerCreateProps>,
349
+ ) {
350
+ return this.load(loadProps, {
351
+ ...container.createProps,
352
+ ...createParamOverrides,
353
+ });
354
+ }
355
+
312
356
  /**
313
357
  * Load an existing container.
314
358
  * @internal
315
359
  */
316
360
  public static async load(
317
- loader: Loader,
318
- loadOptions: IContainerLoadOptions,
319
- pendingLocalState?: IPendingContainerState,
320
- protocolHandlerBuilder?: ProtocolHandlerBuilder,
361
+ loadProps: IContainerLoadProps,
362
+ createProps: IContainerCreateProps,
321
363
  ): Promise<Container> {
322
- const container = new Container(
323
- loader,
324
- {
325
- clientDetailsOverride: loadOptions.clientDetailsOverride,
326
- resolvedUrl: loadOptions.resolvedUrl,
327
- canReconnect: loadOptions.canReconnect,
328
- serializedContainerState: pendingLocalState,
329
- },
330
- protocolHandlerBuilder,
331
- );
364
+ const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
365
+
366
+ const container = new Container(createProps, loadProps);
332
367
 
333
368
  return PerformanceEvent.timedExecAsync(
334
369
  container.mc.logger,
335
370
  { eventName: "Load" },
336
371
  async (event) =>
337
372
  new Promise<Container>((resolve, reject) => {
338
- const version = loadOptions.version;
339
-
340
373
  const defaultMode: IContainerLoadMode = { opsBeforeReturn: "cached" };
341
374
  // if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
342
375
  // to return container, so ignore this value and use undefined for opsBeforeReturn
343
376
  const mode: IContainerLoadMode = pendingLocalState
344
- ? { ...(loadOptions.loadMode ?? defaultMode), opsBeforeReturn: undefined }
345
- : loadOptions.loadMode ?? defaultMode;
377
+ ? { ...(loadMode ?? defaultMode), opsBeforeReturn: undefined }
378
+ : loadMode ?? defaultMode;
346
379
 
347
380
  const onClosed = (err?: ICriticalContainerError) => {
348
381
  // pre-0.58 error message: containerClosedWithoutErrorDuringLoad
@@ -353,13 +386,13 @@ export class Container
353
386
  container.on("closed", onClosed);
354
387
 
355
388
  container
356
- .load(version, mode, pendingLocalState)
389
+ .load(version, mode, resolvedUrl, pendingLocalState)
357
390
  .finally(() => {
358
391
  container.removeListener("closed", onClosed);
359
392
  })
360
393
  .then(
361
394
  (props) => {
362
- event.end({ ...props, ...loadOptions.loadMode });
395
+ event.end({ ...props, ...loadMode });
363
396
  resolve(container);
364
397
  },
365
398
  (error) => {
@@ -380,11 +413,10 @@ export class Container
380
413
  * Create a new container in a detached state.
381
414
  */
382
415
  public static async createDetached(
383
- loader: Loader,
416
+ createProps: IContainerCreateProps,
384
417
  codeDetails: IFluidCodeDetails,
385
- protocolHandlerBuilder?: ProtocolHandlerBuilder,
386
418
  ): Promise<Container> {
387
- const container = new Container(loader, {}, protocolHandlerBuilder);
419
+ const container = new Container(createProps);
388
420
 
389
421
  return PerformanceEvent.timedExecAsync(
390
422
  container.mc.logger,
@@ -402,11 +434,10 @@ export class Container
402
434
  * snapshot from a previous detached container.
403
435
  */
404
436
  public static async rehydrateDetachedFromSnapshot(
405
- loader: Loader,
437
+ createProps: IContainerCreateProps,
406
438
  snapshot: string,
407
- protocolHandlerBuilder?: ProtocolHandlerBuilder,
408
439
  ): Promise<Container> {
409
- const container = new Container(loader, {}, protocolHandlerBuilder);
440
+ const container = new Container(createProps);
410
441
 
411
442
  return PerformanceEvent.timedExecAsync(
412
443
  container.mc.logger,
@@ -502,7 +533,6 @@ export class Container
502
533
  private readonly connectionTransitionTimes: number[] = [];
503
534
  private messageCountAfterDisconnection: number = 0;
504
535
  private _loadedFromVersion: IVersion | undefined;
505
- private _resolvedUrl: IFluidResolvedUrl | undefined;
506
536
  private attachStarted = false;
507
537
  private _dirtyContainer = false;
508
538
  private readonly savedOps: ISequencedDocumentMessage[] = [];
@@ -526,7 +556,18 @@ export class Container
526
556
  }
527
557
 
528
558
  public get resolvedUrl(): IResolvedUrl | undefined {
529
- return this._resolvedUrl;
559
+ /**
560
+ * All attached containers will have a document service,
561
+ * this is required, as attached containers are attached to
562
+ * a service. Detached containers will neither have a document
563
+ * service or a resolved url as they only exist locally.
564
+ * in order to create a document service a resolved url must
565
+ * first be obtained, this is how the container is identified.
566
+ * Because of this, the document service's resolved url
567
+ * is always the same as the containers, as we had to
568
+ * obtain the resolved url, and then create the service from it.
569
+ */
570
+ return this.service?.resolvedUrl;
530
571
  }
531
572
 
532
573
  public get loadedFromVersion(): IVersion | undefined {
@@ -632,17 +673,17 @@ export class Container
632
673
  }
633
674
 
634
675
  private get serviceFactory() {
635
- return this.loader.services.documentServiceFactory;
676
+ return this.createProps.documentServiceFactory;
636
677
  }
637
678
  private get urlResolver() {
638
- return this.loader.services.urlResolver;
679
+ return this.createProps.urlResolver;
639
680
  }
640
681
  public readonly options: ILoaderOptions;
641
682
  private get scope() {
642
- return this.loader.services.scope;
683
+ return this.createProps.scope;
643
684
  }
644
685
  private get codeLoader() {
645
- return this.loader.services.codeLoader;
686
+ return this.createProps.codeLoader;
646
687
  }
647
688
 
648
689
  /**
@@ -684,9 +725,8 @@ export class Container
684
725
  * @internal
685
726
  */
686
727
  constructor(
687
- private readonly loader: Loader,
688
- config: IContainerConfig,
689
- private readonly protocolHandlerBuilder?: ProtocolHandlerBuilder,
728
+ private readonly createProps: IContainerCreateProps,
729
+ loadProps?: IContainerLoadProps,
690
730
  ) {
691
731
  super((name, error) => {
692
732
  this.mc.logger.sendErrorEvent(
@@ -698,10 +738,9 @@ export class Container
698
738
  );
699
739
  });
700
740
 
701
- this.clientDetailsOverride = config.clientDetailsOverride;
702
- this._resolvedUrl = config.resolvedUrl;
703
- if (config.canReconnect !== undefined) {
704
- this._canReconnect = config.canReconnect;
741
+ this.clientDetailsOverride = createProps.clientDetailsOverride;
742
+ if (createProps.canReconnect !== undefined) {
743
+ this._canReconnect = createProps.canReconnect;
705
744
  }
706
745
 
707
746
  // Create logger for data stores to use
@@ -712,15 +751,15 @@ export class Container
712
751
  }`;
713
752
  // Need to use the property getter for docId because for detached flow we don't have the docId initially.
714
753
  // We assign the id later so property getter is used.
715
- this.subLogger = ChildLogger.create(loader.services.subLogger, undefined, {
754
+ this.subLogger = ChildLogger.create(createProps.subLogger, undefined, {
716
755
  all: {
717
756
  clientType, // Differentiating summarizer container from main container
718
757
  containerId: uuid(),
719
- docId: () => this._resolvedUrl?.id ?? undefined,
758
+ docId: () => this.resolvedUrl?.id,
720
759
  containerAttachState: () => this._attachState,
721
760
  containerLifecycleState: () => this._lifecycleState,
722
761
  containerConnectionState: () => ConnectionState[this.connectionState],
723
- serializedContainer: config.serializedContainerState !== undefined,
762
+ serializedContainer: loadProps?.pendingLocalState !== undefined,
724
763
  },
725
764
  // we need to be judicious with our logging here to avoid generating too much data
726
765
  // all data logged here should be broadly applicable, and not specific to a
@@ -750,7 +789,7 @@ export class Container
750
789
  // all clients that were loaded from the same loader (including summarizer clients).
751
790
  // Tracking alternative ways to handle this in AB#4129.
752
791
  this.options = {
753
- ...this.loader.services.options,
792
+ ...this.createProps.options,
754
793
  };
755
794
 
756
795
  this._deltaManager = this.createDeltaManager();
@@ -758,11 +797,11 @@ export class Container
758
797
  this.connectionStateHandler = createConnectionStateHandler(
759
798
  {
760
799
  logger: this.mc.logger,
761
- connectionStateChanged: (value, oldState, reason) => {
800
+ connectionStateChanged: (value, oldState, reason, error) => {
762
801
  if (value === ConnectionState.Connected) {
763
802
  this._clientId = this.connectionStateHandler.pendingClientId;
764
803
  }
765
- this.logConnectionStateChangeTelemetry(value, oldState, reason);
804
+ this.logConnectionStateChangeTelemetry(value, oldState, reason, error);
766
805
  if (this._lifecycleState === "loaded") {
767
806
  this.propagateConnectionState(
768
807
  false /* initial transition */,
@@ -773,7 +812,7 @@ export class Container
773
812
  }
774
813
  },
775
814
  shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
776
- maxClientLeaveWaitTime: this.loader.services.options.maxClientLeaveWaitTime,
815
+ maxClientLeaveWaitTime: this.createProps.options.maxClientLeaveWaitTime,
777
816
  logConnectionIssue: (
778
817
  eventName: string,
779
818
  category: TelemetryEventCategory,
@@ -810,7 +849,7 @@ export class Container
810
849
  },
811
850
  },
812
851
  this.deltaManager,
813
- config.serializedContainerState?.clientId,
852
+ loadProps?.pendingLocalState?.clientId,
814
853
  );
815
854
 
816
855
  this.on(savedContainerEvent, () => {
@@ -829,12 +868,12 @@ export class Container
829
868
  // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
830
869
  const forceEnableSummarizeProtocolTree =
831
870
  this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
832
- this.loader.services.options.summarizeProtocolTree;
871
+ this.createProps.options.summarizeProtocolTree;
833
872
 
834
873
  this.storageAdapter = new ContainerStorageAdapter(
835
- this.loader.services.detachedBlobStorage,
874
+ this.createProps.detachedBlobStorage,
836
875
  this.mc.logger,
837
- config.serializedContainerState?.snapshotBlobs,
876
+ loadProps?.pendingLocalState?.snapshotBlobs,
838
877
  addProtocolSummaryIfMissing,
839
878
  forceEnableSummarizeProtocolTree,
840
879
  );
@@ -868,7 +907,7 @@ export class Container
868
907
  return this.protocolHandler.quorum;
869
908
  }
870
909
 
871
- public dispose?(error?: ICriticalContainerError) {
910
+ public dispose(error?: ICriticalContainerError) {
872
911
  this._deltaManager.close(error, true /* doDispose */);
873
912
  this.verifyClosed();
874
913
  }
@@ -920,15 +959,6 @@ export class Container
920
959
  this._protocolHandler?.close();
921
960
 
922
961
  this.connectionStateHandler.dispose();
923
-
924
- this._context?.dispose(error !== undefined ? new Error(error.message) : undefined);
925
-
926
- this.storageAdapter.dispose();
927
-
928
- // Notify storage about critical errors. They may be due to disconnect between client & server knowledge
929
- // about file, like file being overwritten in storage, but client having stale local cache.
930
- // Driver need to ensure all caches are cleared on critical errors
931
- this.service?.dispose(error);
932
962
  } catch (exception) {
933
963
  this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
934
964
  }
@@ -1048,10 +1078,7 @@ export class Container
1048
1078
  const protocolSummary = this.captureProtocolSummary();
1049
1079
  const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
1050
1080
 
1051
- if (
1052
- this.loader.services.detachedBlobStorage &&
1053
- this.loader.services.detachedBlobStorage.size > 0
1054
- ) {
1081
+ if (this.createProps.detachedBlobStorage && this.createProps.detachedBlobStorage.size > 0) {
1055
1082
  combinedSummary.tree[".hasAttachmentBlobs"] = {
1056
1083
  type: SummaryType.Blob,
1057
1084
  content: "true",
@@ -1081,8 +1108,8 @@ export class Container
1081
1108
 
1082
1109
  // If attachment blobs were uploaded in detached state we will go through a different attach flow
1083
1110
  const hasAttachmentBlobs =
1084
- this.loader.services.detachedBlobStorage !== undefined &&
1085
- this.loader.services.detachedBlobStorage.size > 0;
1111
+ this.createProps.detachedBlobStorage !== undefined &&
1112
+ this.createProps.detachedBlobStorage.size > 0;
1086
1113
 
1087
1114
  try {
1088
1115
  assert(
@@ -1113,11 +1140,11 @@ export class Container
1113
1140
  }
1114
1141
 
1115
1142
  // Actually go and create the resolved document
1116
- const createNewResolvedUrl = await this.urlResolver.resolve(request);
1117
- ensureFluidResolvedUrl(createNewResolvedUrl);
1118
1143
  if (this.service === undefined) {
1144
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
1119
1145
  assert(
1120
- this.client.details.type !== summarizerClientType,
1146
+ this.client.details.type !== summarizerClientType &&
1147
+ createNewResolvedUrl !== undefined,
1121
1148
  0x2c4 /* "client should not be summarizer before container is created" */,
1122
1149
  );
1123
1150
  this.service = await runWithRetry(
@@ -1135,15 +1162,12 @@ export class Container
1135
1162
  }, // progress
1136
1163
  );
1137
1164
  }
1138
- const resolvedUrl = this.service.resolvedUrl;
1139
- ensureFluidResolvedUrl(resolvedUrl);
1140
- this._resolvedUrl = resolvedUrl;
1141
1165
  await this.storageAdapter.connectToService(this.service);
1142
1166
 
1143
1167
  if (hasAttachmentBlobs) {
1144
1168
  // upload blobs to storage
1145
1169
  assert(
1146
- !!this.loader.services.detachedBlobStorage,
1170
+ !!this.createProps.detachedBlobStorage,
1147
1171
  0x24e /* "assertion for type narrowing" */,
1148
1172
  );
1149
1173
 
@@ -1151,13 +1175,14 @@ export class Container
1151
1175
  // support blob handles that only know about the local IDs
1152
1176
  const redirectTable = new Map<string, string>();
1153
1177
  // if new blobs are added while uploading, upload them too
1154
- while (redirectTable.size < this.loader.services.detachedBlobStorage.size) {
1155
- const newIds = this.loader.services.detachedBlobStorage
1178
+ while (redirectTable.size < this.createProps.detachedBlobStorage.size) {
1179
+ const newIds = this.createProps.detachedBlobStorage
1156
1180
  .getBlobIds()
1157
1181
  .filter((id) => !redirectTable.has(id));
1158
1182
  for (const id of newIds) {
1159
- const blob =
1160
- await this.loader.services.detachedBlobStorage.readBlob(id);
1183
+ const blob = await this.createProps.detachedBlobStorage.readBlob(
1184
+ id,
1185
+ );
1161
1186
  const response = await this.storageAdapter.createBlob(blob);
1162
1187
  redirectTable.set(id, response.id);
1163
1188
  }
@@ -1196,12 +1221,8 @@ export class Container
1196
1221
  } catch (error) {
1197
1222
  // add resolved URL on error object so that host has the ability to find this document and delete it
1198
1223
  const newError = normalizeError(error);
1199
- const resolvedUrl = this.resolvedUrl;
1200
- if (isFluidResolvedUrl(resolvedUrl)) {
1201
- newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
1202
- }
1224
+ newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
1203
1225
  this.close(newError);
1204
- this.dispose?.(newError);
1205
1226
  throw newError;
1206
1227
  }
1207
1228
  },
@@ -1348,7 +1369,6 @@ export class Container
1348
1369
  // pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
1349
1370
  const error = new GenericError("Existing context does not satisfy incoming proposal");
1350
1371
  this.close(error);
1351
- this.dispose?.(error);
1352
1372
  }
1353
1373
 
1354
1374
  private async getVersion(version: string | null): Promise<IVersion | undefined> {
@@ -1381,13 +1401,11 @@ export class Container
1381
1401
  private async load(
1382
1402
  specifiedVersion: string | undefined,
1383
1403
  loadMode: IContainerLoadMode,
1404
+ resolvedUrl: IResolvedUrl,
1384
1405
  pendingLocalState?: IPendingContainerState,
1385
1406
  ) {
1386
- if (this._resolvedUrl === undefined) {
1387
- throw new Error("Attempting to load without a resolved url");
1388
- }
1389
1407
  this.service = await this.serviceFactory.createDocumentService(
1390
- this._resolvedUrl,
1408
+ resolvedUrl,
1391
1409
  this.subLogger,
1392
1410
  this.client.details.type === summarizerClientType,
1393
1411
  );
@@ -1419,7 +1437,6 @@ export class Container
1419
1437
  // if we have pendingLocalState we can load without storage; don't wait for connection
1420
1438
  this.storageAdapter.connectToService(this.service).catch((error) => {
1421
1439
  this.close(error);
1422
- this.dispose?.(error);
1423
1440
  });
1424
1441
  }
1425
1442
 
@@ -1602,8 +1619,8 @@ export class Container
1602
1619
  private async rehydrateDetachedFromSnapshot(detachedContainerSnapshot: ISummaryTree) {
1603
1620
  if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
1604
1621
  assert(
1605
- !!this.loader.services.detachedBlobStorage &&
1606
- this.loader.services.detachedBlobStorage.size > 0,
1622
+ !!this.createProps.detachedBlobStorage &&
1623
+ this.createProps.detachedBlobStorage.size > 0,
1607
1624
  0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
1608
1625
  );
1609
1626
  delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
@@ -1701,7 +1718,7 @@ export class Container
1701
1718
  quorumSnapshot: IQuorumSnapshot,
1702
1719
  ): void {
1703
1720
  const protocolHandlerBuilder =
1704
- this.protocolHandlerBuilder ??
1721
+ this.createProps.protocolHandlerBuilder ??
1705
1722
  ((...args) => new ProtocolHandler(...args, new Audience()));
1706
1723
  const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) =>
1707
1724
  this.submitMessage(MessageType.Propose, JSON.stringify({ key, value })),
@@ -1732,7 +1749,6 @@ export class Container
1732
1749
  this.processCodeProposal().catch((error) => {
1733
1750
  const normalizedError = normalizeError(error);
1734
1751
  this.close(normalizedError);
1735
- this.dispose?.(normalizedError);
1736
1752
  throw error;
1737
1753
  });
1738
1754
  }
@@ -1843,10 +1859,10 @@ export class Container
1843
1859
  this.connectionStateHandler.receivedConnectEvent(details);
1844
1860
  });
1845
1861
 
1846
- deltaManager.on("disconnect", (reason: string) => {
1862
+ deltaManager.on("disconnect", (reason: string, error?: IAnyDriverError) => {
1847
1863
  this.collabWindowTracker?.stopSequenceNumberUpdate();
1848
1864
  if (!this.closed) {
1849
- this.connectionStateHandler.receivedDisconnectEvent(reason);
1865
+ this.connectionStateHandler.receivedDisconnectEvent(reason, error);
1850
1866
  }
1851
1867
  });
1852
1868
 
@@ -1900,6 +1916,7 @@ export class Container
1900
1916
  value: ConnectionState,
1901
1917
  oldState: ConnectionState,
1902
1918
  reason?: string,
1919
+ error?: IAnyDriverError,
1903
1920
  ) {
1904
1921
  // Log actual event
1905
1922
  const time = performance.now();
@@ -1928,24 +1945,29 @@ export class Container
1928
1945
  connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
1929
1946
  }
1930
1947
 
1931
- this.mc.logger.sendPerformanceEvent({
1932
- eventName: `ConnectionStateChange_${ConnectionState[value]}`,
1933
- from: ConnectionState[oldState],
1934
- duration,
1935
- durationFromDisconnected,
1936
- reason,
1937
- connectionInitiationReason,
1938
- pendingClientId: this.connectionStateHandler.pendingClientId,
1939
- clientId: this.clientId,
1940
- autoReconnect,
1941
- opsBehind,
1942
- online: OnlineStatus[isOnline()],
1943
- lastVisible:
1944
- this.lastVisible !== undefined ? performance.now() - this.lastVisible : undefined,
1945
- checkpointSequenceNumber,
1946
- quorumSize: this._protocolHandler?.quorum.getMembers().size,
1947
- ...this._deltaManager.connectionProps,
1948
- });
1948
+ this.mc.logger.sendPerformanceEvent(
1949
+ {
1950
+ eventName: `ConnectionStateChange_${ConnectionState[value]}`,
1951
+ from: ConnectionState[oldState],
1952
+ duration,
1953
+ durationFromDisconnected,
1954
+ reason,
1955
+ connectionInitiationReason,
1956
+ pendingClientId: this.connectionStateHandler.pendingClientId,
1957
+ clientId: this.clientId,
1958
+ autoReconnect,
1959
+ opsBehind,
1960
+ online: OnlineStatus[isOnline()],
1961
+ lastVisible:
1962
+ this.lastVisible !== undefined
1963
+ ? performance.now() - this.lastVisible
1964
+ : undefined,
1965
+ checkpointSequenceNumber,
1966
+ quorumSize: this._protocolHandler?.quorum.getMembers().size,
1967
+ ...this._deltaManager.connectionProps,
1968
+ },
1969
+ error,
1970
+ );
1949
1971
 
1950
1972
  if (value === ConnectionState.Connected) {
1951
1973
  this.firstConnection = false;
@@ -2006,7 +2028,6 @@ export class Container
2006
2028
  { messageType: type },
2007
2029
  );
2008
2030
  this.close(newError);
2009
- this.dispose?.(newError);
2010
2031
  return -1;
2011
2032
  }
2012
2033
  }
@@ -2176,7 +2197,8 @@ export class Container
2176
2197
 
2177
2198
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
2178
2199
  // are set. Global requests will still go directly to the loader
2179
- const loader = new RelativeLoader(this, this.loader);
2200
+ const maybeLoader: FluidObject<IHostLoader> = this.scope;
2201
+ const loader = new RelativeLoader(this, maybeLoader.ILoader);
2180
2202
  this._context = await ContainerContext.createOrLoad(
2181
2203
  this,
2182
2204
  this.scope,
@@ -2193,7 +2215,7 @@ export class Container
2193
2215
  (batch: IBatchMessage[], referenceSequenceNumber?: number) =>
2194
2216
  this.submitBatch(batch, referenceSequenceNumber),
2195
2217
  (message) => this.submitSignal(message),
2196
- (error?: ICriticalContainerError) => this.dispose?.(error),
2218
+ (error?: ICriticalContainerError) => this.dispose(error),
2197
2219
  (error?: ICriticalContainerError) => this.close(error),
2198
2220
  Container.version,
2199
2221
  (dirty: boolean) => this.updateDirtyContainerState(dirty),