@fluidframework/container-loader 2.0.0-internal.4.4.1 → 2.0.0-internal.5.0.1

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 (84) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +6 -3
  3. package/dist/connectionManager.d.ts +3 -2
  4. package/dist/connectionManager.d.ts.map +1 -1
  5. package/dist/connectionManager.js.map +1 -1
  6. package/dist/connectionStateHandler.d.ts +4 -3
  7. package/dist/connectionStateHandler.d.ts.map +1 -1
  8. package/dist/connectionStateHandler.js.map +1 -1
  9. package/dist/container.d.ts +62 -36
  10. package/dist/container.d.ts.map +1 -1
  11. package/dist/container.js +63 -83
  12. package/dist/container.js.map +1 -1
  13. package/dist/containerContext.d.ts +2 -2
  14. package/dist/containerContext.d.ts.map +1 -1
  15. package/dist/containerContext.js +3 -7
  16. package/dist/containerContext.js.map +1 -1
  17. package/dist/containerStorageAdapter.d.ts +3 -3
  18. package/dist/containerStorageAdapter.d.ts.map +1 -1
  19. package/dist/containerStorageAdapter.js.map +1 -1
  20. package/dist/deltaManager.d.ts +3 -2
  21. package/dist/deltaManager.d.ts.map +1 -1
  22. package/dist/deltaManager.js +0 -1
  23. package/dist/deltaManager.js.map +1 -1
  24. package/dist/index.d.ts +1 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/loader.d.ts +9 -5
  28. package/dist/loader.d.ts.map +1 -1
  29. package/dist/loader.js +28 -34
  30. package/dist/loader.js.map +1 -1
  31. package/dist/packageVersion.d.ts +1 -1
  32. package/dist/packageVersion.js +1 -1
  33. package/dist/packageVersion.js.map +1 -1
  34. package/dist/retriableDocumentStorageService.d.ts +3 -2
  35. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  36. package/dist/retriableDocumentStorageService.js.map +1 -1
  37. package/lib/connectionManager.d.ts +3 -2
  38. package/lib/connectionManager.d.ts.map +1 -1
  39. package/lib/connectionManager.js +1 -1
  40. package/lib/connectionManager.js.map +1 -1
  41. package/lib/connectionStateHandler.d.ts +4 -3
  42. package/lib/connectionStateHandler.d.ts.map +1 -1
  43. package/lib/connectionStateHandler.js +1 -1
  44. package/lib/connectionStateHandler.js.map +1 -1
  45. package/lib/container.d.ts +62 -36
  46. package/lib/container.d.ts.map +1 -1
  47. package/lib/container.js +64 -84
  48. package/lib/container.js.map +1 -1
  49. package/lib/containerContext.d.ts +2 -2
  50. package/lib/containerContext.d.ts.map +1 -1
  51. package/lib/containerContext.js +3 -7
  52. package/lib/containerContext.js.map +1 -1
  53. package/lib/containerStorageAdapter.d.ts +3 -3
  54. package/lib/containerStorageAdapter.d.ts.map +1 -1
  55. package/lib/containerStorageAdapter.js.map +1 -1
  56. package/lib/deltaManager.d.ts +3 -2
  57. package/lib/deltaManager.d.ts.map +1 -1
  58. package/lib/deltaManager.js +1 -2
  59. package/lib/deltaManager.js.map +1 -1
  60. package/lib/index.d.ts +1 -2
  61. package/lib/index.d.ts.map +1 -1
  62. package/lib/index.js +1 -1
  63. package/lib/index.js.map +1 -1
  64. package/lib/loader.d.ts +9 -5
  65. package/lib/loader.d.ts.map +1 -1
  66. package/lib/loader.js +28 -34
  67. package/lib/loader.js.map +1 -1
  68. package/lib/packageVersion.d.ts +1 -1
  69. package/lib/packageVersion.js +1 -1
  70. package/lib/packageVersion.js.map +1 -1
  71. package/lib/retriableDocumentStorageService.d.ts +3 -2
  72. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  73. package/lib/retriableDocumentStorageService.js.map +1 -1
  74. package/package.json +27 -10
  75. package/src/connectionManager.ts +7 -7
  76. package/src/connectionStateHandler.ts +7 -7
  77. package/src/container.ts +140 -125
  78. package/src/containerContext.ts +3 -9
  79. package/src/containerStorageAdapter.ts +4 -4
  80. package/src/deltaManager.ts +7 -4
  81. package/src/index.ts +1 -8
  82. package/src/loader.ts +56 -47
  83. package/src/packageVersion.ts +1 -1
  84. 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,23 +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 {
35
33
  IAnyDriverError,
36
34
  IDocumentService,
35
+ IDocumentServiceFactory,
37
36
  IDocumentStorageService,
38
- IFluidResolvedUrl,
39
37
  IResolvedUrl,
38
+ IUrlResolver,
40
39
  } from "@fluidframework/driver-definitions";
41
40
  import {
42
41
  readAndParse,
43
42
  OnlineStatus,
44
43
  isOnline,
45
- ensureFluidResolvedUrl,
46
44
  combineAppAndProtocolSummary,
47
45
  runWithRetry,
48
- isFluidResolvedUrl,
49
46
  isCombinedAppAndProtocolSummary,
50
47
  } from "@fluidframework/driver-utils";
51
48
  import { IQuorumSnapshot } from "@fluidframework/protocol-base";
@@ -80,13 +77,14 @@ import {
80
77
  MonitoringContext,
81
78
  loggerToMonitoringContext,
82
79
  wrapError,
80
+ ITelemetryLoggerExt,
83
81
  } from "@fluidframework/telemetry-utils";
84
82
  import { Audience } from "./audience";
85
83
  import { ContainerContext } from "./containerContext";
86
84
  import { ReconnectMode, IConnectionManagerFactoryArgs, getPackageName } from "./contracts";
87
85
  import { DeltaManager, IConnectionArgs } from "./deltaManager";
88
86
  import { DeltaManagerProxy } from "./deltaManagerProxy";
89
- import { ILoaderOptions, Loader, RelativeLoader } from "./loader";
87
+ import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader";
90
88
  import { pkgVersion } from "./packageVersion";
91
89
  import {
92
90
  ContainerStorageAdapter,
@@ -117,44 +115,82 @@ const dirtyContainerEvent = "dirty";
117
115
  const savedContainerEvent = "saved";
118
116
 
119
117
  /**
120
- * @deprecated this is an internal interface and will not longer be exported in future versions
121
118
  * @internal
122
119
  */
123
- export interface IContainerLoadOptions {
120
+ export interface IContainerLoadProps {
124
121
  /**
125
- * Disables the Container from reconnecting if false, allows reconnect otherwise.
122
+ * The resolved url of the container being loaded
126
123
  */
127
- canReconnect?: boolean;
128
- /**
129
- * Client details provided in the override will be merged over the default client.
130
- */
131
- clientDetailsOverride?: IClientDetails;
132
- resolvedUrl: IFluidResolvedUrl;
124
+ readonly resolvedUrl: IResolvedUrl;
133
125
  /**
134
126
  * Control which snapshot version to load from. See IParsedUrl for detailed information.
135
127
  */
136
- version: string | undefined;
128
+ readonly version: string | undefined;
137
129
  /**
138
130
  * Loads the Container in paused state if true, unpaused otherwise.
139
131
  */
140
- loadMode?: IContainerLoadMode;
132
+ readonly loadMode?: IContainerLoadMode;
133
+
134
+ /**
135
+ * The pending state serialized from a pervious container instance
136
+ */
137
+ readonly pendingLocalState?: IPendingContainerState;
141
138
  }
142
139
 
143
140
  /**
144
- * @deprecated this is an internal interface and will not longer be exported in future versions
145
141
  * @internal
146
142
  */
147
- export interface IContainerConfig {
148
- resolvedUrl?: IFluidResolvedUrl;
149
- canReconnect?: boolean;
143
+ export interface IContainerCreateProps {
144
+ /**
145
+ * Disables the Container from reconnecting if false, allows reconnect otherwise.
146
+ */
147
+ readonly canReconnect?: boolean;
150
148
  /**
151
149
  * Client details provided in the override will be merged over the default client.
152
150
  */
153
- 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;
165
+ /**
166
+ * The code loader handles loading the necessary code
167
+ * for running a container once it is loaded.
168
+ */
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
+
154
188
  /**
155
- * Serialized state from a previous instance of this container
189
+ * Blobs storage for detached containers.
156
190
  */
157
- serializedContainerState?: IPendingContainerState;
191
+ readonly detachedBlobStorage?: IDetachedBlobStorage;
192
+
193
+ readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
158
194
  }
159
195
 
160
196
  /**
@@ -260,7 +296,7 @@ const getCodeProposal =
260
296
  * @param action - functor to call and measure
261
297
  */
262
298
  export async function ReportIfTooLong(
263
- logger: ITelemetryLogger,
299
+ logger: ITelemetryLoggerExt,
264
300
  eventName: string,
265
301
  action: () => Promise<ITelemetryProperties>,
266
302
  ) {
@@ -274,7 +310,6 @@ export async function ReportIfTooLong(
274
310
  /**
275
311
  * State saved by a container at close time, to be used to load a new instance
276
312
  * of the container to the same state
277
- * @deprecated this is an internal interface and will not longer be exported in future versions
278
313
  * @internal
279
314
  */
280
315
  export interface IPendingContainerState {
@@ -301,49 +336,46 @@ export interface IPendingContainerState {
301
336
 
302
337
  const summarizerClientType = "summarizer";
303
338
 
304
- /**
305
- * @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
306
- */
307
339
  export class Container
308
340
  extends EventEmitterWithErrorHandling<IContainerEvents>
309
341
  implements IContainer, IContainerExperimental
310
342
  {
311
343
  public static version = "^0.1.0";
312
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
+
313
356
  /**
314
357
  * Load an existing container.
315
358
  * @internal
316
359
  */
317
360
  public static async load(
318
- loader: Loader,
319
- loadOptions: IContainerLoadOptions,
320
- pendingLocalState?: IPendingContainerState,
321
- protocolHandlerBuilder?: ProtocolHandlerBuilder,
361
+ loadProps: IContainerLoadProps,
362
+ createProps: IContainerCreateProps,
322
363
  ): Promise<Container> {
323
- const container = new Container(
324
- loader,
325
- {
326
- clientDetailsOverride: loadOptions.clientDetailsOverride,
327
- resolvedUrl: loadOptions.resolvedUrl,
328
- canReconnect: loadOptions.canReconnect,
329
- serializedContainerState: pendingLocalState,
330
- },
331
- protocolHandlerBuilder,
332
- );
364
+ const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
365
+
366
+ const container = new Container(createProps, loadProps);
333
367
 
334
368
  return PerformanceEvent.timedExecAsync(
335
369
  container.mc.logger,
336
370
  { eventName: "Load" },
337
371
  async (event) =>
338
372
  new Promise<Container>((resolve, reject) => {
339
- const version = loadOptions.version;
340
-
341
373
  const defaultMode: IContainerLoadMode = { opsBeforeReturn: "cached" };
342
374
  // if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
343
375
  // to return container, so ignore this value and use undefined for opsBeforeReturn
344
376
  const mode: IContainerLoadMode = pendingLocalState
345
- ? { ...(loadOptions.loadMode ?? defaultMode), opsBeforeReturn: undefined }
346
- : loadOptions.loadMode ?? defaultMode;
377
+ ? { ...(loadMode ?? defaultMode), opsBeforeReturn: undefined }
378
+ : loadMode ?? defaultMode;
347
379
 
348
380
  const onClosed = (err?: ICriticalContainerError) => {
349
381
  // pre-0.58 error message: containerClosedWithoutErrorDuringLoad
@@ -354,13 +386,13 @@ export class Container
354
386
  container.on("closed", onClosed);
355
387
 
356
388
  container
357
- .load(version, mode, pendingLocalState)
389
+ .load(version, mode, resolvedUrl, pendingLocalState)
358
390
  .finally(() => {
359
391
  container.removeListener("closed", onClosed);
360
392
  })
361
393
  .then(
362
394
  (props) => {
363
- event.end({ ...props, ...loadOptions.loadMode });
395
+ event.end({ ...props, ...loadMode });
364
396
  resolve(container);
365
397
  },
366
398
  (error) => {
@@ -381,11 +413,10 @@ export class Container
381
413
  * Create a new container in a detached state.
382
414
  */
383
415
  public static async createDetached(
384
- loader: Loader,
416
+ createProps: IContainerCreateProps,
385
417
  codeDetails: IFluidCodeDetails,
386
- protocolHandlerBuilder?: ProtocolHandlerBuilder,
387
418
  ): Promise<Container> {
388
- const container = new Container(loader, {}, protocolHandlerBuilder);
419
+ const container = new Container(createProps);
389
420
 
390
421
  return PerformanceEvent.timedExecAsync(
391
422
  container.mc.logger,
@@ -403,11 +434,10 @@ export class Container
403
434
  * snapshot from a previous detached container.
404
435
  */
405
436
  public static async rehydrateDetachedFromSnapshot(
406
- loader: Loader,
437
+ createProps: IContainerCreateProps,
407
438
  snapshot: string,
408
- protocolHandlerBuilder?: ProtocolHandlerBuilder,
409
439
  ): Promise<Container> {
410
- const container = new Container(loader, {}, protocolHandlerBuilder);
440
+ const container = new Container(createProps);
411
441
 
412
442
  return PerformanceEvent.timedExecAsync(
413
443
  container.mc.logger,
@@ -503,7 +533,6 @@ export class Container
503
533
  private readonly connectionTransitionTimes: number[] = [];
504
534
  private messageCountAfterDisconnection: number = 0;
505
535
  private _loadedFromVersion: IVersion | undefined;
506
- private _resolvedUrl: IFluidResolvedUrl | undefined;
507
536
  private attachStarted = false;
508
537
  private _dirtyContainer = false;
509
538
  private readonly savedOps: ISequencedDocumentMessage[] = [];
@@ -527,7 +556,18 @@ export class Container
527
556
  }
528
557
 
529
558
  public get resolvedUrl(): IResolvedUrl | undefined {
530
- 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;
531
571
  }
532
572
 
533
573
  public get loadedFromVersion(): IVersion | undefined {
@@ -633,17 +673,17 @@ export class Container
633
673
  }
634
674
 
635
675
  private get serviceFactory() {
636
- return this.loader.services.documentServiceFactory;
676
+ return this.createProps.documentServiceFactory;
637
677
  }
638
678
  private get urlResolver() {
639
- return this.loader.services.urlResolver;
679
+ return this.createProps.urlResolver;
640
680
  }
641
681
  public readonly options: ILoaderOptions;
642
682
  private get scope() {
643
- return this.loader.services.scope;
683
+ return this.createProps.scope;
644
684
  }
645
685
  private get codeLoader() {
646
- return this.loader.services.codeLoader;
686
+ return this.createProps.codeLoader;
647
687
  }
648
688
 
649
689
  /**
@@ -685,9 +725,8 @@ export class Container
685
725
  * @internal
686
726
  */
687
727
  constructor(
688
- private readonly loader: Loader,
689
- config: IContainerConfig,
690
- private readonly protocolHandlerBuilder?: ProtocolHandlerBuilder,
728
+ private readonly createProps: IContainerCreateProps,
729
+ loadProps?: IContainerLoadProps,
691
730
  ) {
692
731
  super((name, error) => {
693
732
  this.mc.logger.sendErrorEvent(
@@ -699,10 +738,9 @@ export class Container
699
738
  );
700
739
  });
701
740
 
702
- this.clientDetailsOverride = config.clientDetailsOverride;
703
- this._resolvedUrl = config.resolvedUrl;
704
- if (config.canReconnect !== undefined) {
705
- this._canReconnect = config.canReconnect;
741
+ this.clientDetailsOverride = createProps.clientDetailsOverride;
742
+ if (createProps.canReconnect !== undefined) {
743
+ this._canReconnect = createProps.canReconnect;
706
744
  }
707
745
 
708
746
  // Create logger for data stores to use
@@ -713,15 +751,15 @@ export class Container
713
751
  }`;
714
752
  // Need to use the property getter for docId because for detached flow we don't have the docId initially.
715
753
  // We assign the id later so property getter is used.
716
- this.subLogger = ChildLogger.create(loader.services.subLogger, undefined, {
754
+ this.subLogger = ChildLogger.create(createProps.subLogger, undefined, {
717
755
  all: {
718
756
  clientType, // Differentiating summarizer container from main container
719
757
  containerId: uuid(),
720
- docId: () => this._resolvedUrl?.id ?? undefined,
758
+ docId: () => this.resolvedUrl?.id,
721
759
  containerAttachState: () => this._attachState,
722
760
  containerLifecycleState: () => this._lifecycleState,
723
761
  containerConnectionState: () => ConnectionState[this.connectionState],
724
- serializedContainer: config.serializedContainerState !== undefined,
762
+ serializedContainer: loadProps?.pendingLocalState !== undefined,
725
763
  },
726
764
  // we need to be judicious with our logging here to avoid generating too much data
727
765
  // all data logged here should be broadly applicable, and not specific to a
@@ -751,7 +789,7 @@ export class Container
751
789
  // all clients that were loaded from the same loader (including summarizer clients).
752
790
  // Tracking alternative ways to handle this in AB#4129.
753
791
  this.options = {
754
- ...this.loader.services.options,
792
+ ...this.createProps.options,
755
793
  };
756
794
 
757
795
  this._deltaManager = this.createDeltaManager();
@@ -774,7 +812,7 @@ export class Container
774
812
  }
775
813
  },
776
814
  shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
777
- maxClientLeaveWaitTime: this.loader.services.options.maxClientLeaveWaitTime,
815
+ maxClientLeaveWaitTime: this.createProps.options.maxClientLeaveWaitTime,
778
816
  logConnectionIssue: (
779
817
  eventName: string,
780
818
  category: TelemetryEventCategory,
@@ -811,7 +849,7 @@ export class Container
811
849
  },
812
850
  },
813
851
  this.deltaManager,
814
- config.serializedContainerState?.clientId,
852
+ loadProps?.pendingLocalState?.clientId,
815
853
  );
816
854
 
817
855
  this.on(savedContainerEvent, () => {
@@ -830,12 +868,12 @@ export class Container
830
868
  // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
831
869
  const forceEnableSummarizeProtocolTree =
832
870
  this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
833
- this.loader.services.options.summarizeProtocolTree;
871
+ this.createProps.options.summarizeProtocolTree;
834
872
 
835
873
  this.storageAdapter = new ContainerStorageAdapter(
836
- this.loader.services.detachedBlobStorage,
874
+ this.createProps.detachedBlobStorage,
837
875
  this.mc.logger,
838
- config.serializedContainerState?.snapshotBlobs,
876
+ loadProps?.pendingLocalState?.snapshotBlobs,
839
877
  addProtocolSummaryIfMissing,
840
878
  forceEnableSummarizeProtocolTree,
841
879
  );
@@ -869,7 +907,7 @@ export class Container
869
907
  return this.protocolHandler.quorum;
870
908
  }
871
909
 
872
- public dispose?(error?: ICriticalContainerError) {
910
+ public dispose(error?: ICriticalContainerError) {
873
911
  this._deltaManager.close(error, true /* doDispose */);
874
912
  this.verifyClosed();
875
913
  }
@@ -921,15 +959,6 @@ export class Container
921
959
  this._protocolHandler?.close();
922
960
 
923
961
  this.connectionStateHandler.dispose();
924
-
925
- this._context?.dispose(error !== undefined ? new Error(error.message) : undefined);
926
-
927
- this.storageAdapter.dispose();
928
-
929
- // Notify storage about critical errors. They may be due to disconnect between client & server knowledge
930
- // about file, like file being overwritten in storage, but client having stale local cache.
931
- // Driver need to ensure all caches are cleared on critical errors
932
- this.service?.dispose(error);
933
962
  } catch (exception) {
934
963
  this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
935
964
  }
@@ -1049,10 +1078,7 @@ export class Container
1049
1078
  const protocolSummary = this.captureProtocolSummary();
1050
1079
  const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
1051
1080
 
1052
- if (
1053
- this.loader.services.detachedBlobStorage &&
1054
- this.loader.services.detachedBlobStorage.size > 0
1055
- ) {
1081
+ if (this.createProps.detachedBlobStorage && this.createProps.detachedBlobStorage.size > 0) {
1056
1082
  combinedSummary.tree[".hasAttachmentBlobs"] = {
1057
1083
  type: SummaryType.Blob,
1058
1084
  content: "true",
@@ -1082,8 +1108,8 @@ export class Container
1082
1108
 
1083
1109
  // If attachment blobs were uploaded in detached state we will go through a different attach flow
1084
1110
  const hasAttachmentBlobs =
1085
- this.loader.services.detachedBlobStorage !== undefined &&
1086
- this.loader.services.detachedBlobStorage.size > 0;
1111
+ this.createProps.detachedBlobStorage !== undefined &&
1112
+ this.createProps.detachedBlobStorage.size > 0;
1087
1113
 
1088
1114
  try {
1089
1115
  assert(
@@ -1114,11 +1140,11 @@ export class Container
1114
1140
  }
1115
1141
 
1116
1142
  // Actually go and create the resolved document
1117
- const createNewResolvedUrl = await this.urlResolver.resolve(request);
1118
- ensureFluidResolvedUrl(createNewResolvedUrl);
1119
1143
  if (this.service === undefined) {
1144
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
1120
1145
  assert(
1121
- this.client.details.type !== summarizerClientType,
1146
+ this.client.details.type !== summarizerClientType &&
1147
+ createNewResolvedUrl !== undefined,
1122
1148
  0x2c4 /* "client should not be summarizer before container is created" */,
1123
1149
  );
1124
1150
  this.service = await runWithRetry(
@@ -1136,15 +1162,12 @@ export class Container
1136
1162
  }, // progress
1137
1163
  );
1138
1164
  }
1139
- const resolvedUrl = this.service.resolvedUrl;
1140
- ensureFluidResolvedUrl(resolvedUrl);
1141
- this._resolvedUrl = resolvedUrl;
1142
1165
  await this.storageAdapter.connectToService(this.service);
1143
1166
 
1144
1167
  if (hasAttachmentBlobs) {
1145
1168
  // upload blobs to storage
1146
1169
  assert(
1147
- !!this.loader.services.detachedBlobStorage,
1170
+ !!this.createProps.detachedBlobStorage,
1148
1171
  0x24e /* "assertion for type narrowing" */,
1149
1172
  );
1150
1173
 
@@ -1152,13 +1175,14 @@ export class Container
1152
1175
  // support blob handles that only know about the local IDs
1153
1176
  const redirectTable = new Map<string, string>();
1154
1177
  // if new blobs are added while uploading, upload them too
1155
- while (redirectTable.size < this.loader.services.detachedBlobStorage.size) {
1156
- const newIds = this.loader.services.detachedBlobStorage
1178
+ while (redirectTable.size < this.createProps.detachedBlobStorage.size) {
1179
+ const newIds = this.createProps.detachedBlobStorage
1157
1180
  .getBlobIds()
1158
1181
  .filter((id) => !redirectTable.has(id));
1159
1182
  for (const id of newIds) {
1160
- const blob =
1161
- await this.loader.services.detachedBlobStorage.readBlob(id);
1183
+ const blob = await this.createProps.detachedBlobStorage.readBlob(
1184
+ id,
1185
+ );
1162
1186
  const response = await this.storageAdapter.createBlob(blob);
1163
1187
  redirectTable.set(id, response.id);
1164
1188
  }
@@ -1197,12 +1221,8 @@ export class Container
1197
1221
  } catch (error) {
1198
1222
  // add resolved URL on error object so that host has the ability to find this document and delete it
1199
1223
  const newError = normalizeError(error);
1200
- const resolvedUrl = this.resolvedUrl;
1201
- if (isFluidResolvedUrl(resolvedUrl)) {
1202
- newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
1203
- }
1224
+ newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
1204
1225
  this.close(newError);
1205
- this.dispose?.(newError);
1206
1226
  throw newError;
1207
1227
  }
1208
1228
  },
@@ -1349,7 +1369,6 @@ export class Container
1349
1369
  // pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
1350
1370
  const error = new GenericError("Existing context does not satisfy incoming proposal");
1351
1371
  this.close(error);
1352
- this.dispose?.(error);
1353
1372
  }
1354
1373
 
1355
1374
  private async getVersion(version: string | null): Promise<IVersion | undefined> {
@@ -1382,13 +1401,11 @@ export class Container
1382
1401
  private async load(
1383
1402
  specifiedVersion: string | undefined,
1384
1403
  loadMode: IContainerLoadMode,
1404
+ resolvedUrl: IResolvedUrl,
1385
1405
  pendingLocalState?: IPendingContainerState,
1386
1406
  ) {
1387
- if (this._resolvedUrl === undefined) {
1388
- throw new Error("Attempting to load without a resolved url");
1389
- }
1390
1407
  this.service = await this.serviceFactory.createDocumentService(
1391
- this._resolvedUrl,
1408
+ resolvedUrl,
1392
1409
  this.subLogger,
1393
1410
  this.client.details.type === summarizerClientType,
1394
1411
  );
@@ -1420,7 +1437,6 @@ export class Container
1420
1437
  // if we have pendingLocalState we can load without storage; don't wait for connection
1421
1438
  this.storageAdapter.connectToService(this.service).catch((error) => {
1422
1439
  this.close(error);
1423
- this.dispose?.(error);
1424
1440
  });
1425
1441
  }
1426
1442
 
@@ -1603,8 +1619,8 @@ export class Container
1603
1619
  private async rehydrateDetachedFromSnapshot(detachedContainerSnapshot: ISummaryTree) {
1604
1620
  if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
1605
1621
  assert(
1606
- !!this.loader.services.detachedBlobStorage &&
1607
- this.loader.services.detachedBlobStorage.size > 0,
1622
+ !!this.createProps.detachedBlobStorage &&
1623
+ this.createProps.detachedBlobStorage.size > 0,
1608
1624
  0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
1609
1625
  );
1610
1626
  delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
@@ -1702,7 +1718,7 @@ export class Container
1702
1718
  quorumSnapshot: IQuorumSnapshot,
1703
1719
  ): void {
1704
1720
  const protocolHandlerBuilder =
1705
- this.protocolHandlerBuilder ??
1721
+ this.createProps.protocolHandlerBuilder ??
1706
1722
  ((...args) => new ProtocolHandler(...args, new Audience()));
1707
1723
  const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) =>
1708
1724
  this.submitMessage(MessageType.Propose, JSON.stringify({ key, value })),
@@ -1733,7 +1749,6 @@ export class Container
1733
1749
  this.processCodeProposal().catch((error) => {
1734
1750
  const normalizedError = normalizeError(error);
1735
1751
  this.close(normalizedError);
1736
- this.dispose?.(normalizedError);
1737
1752
  throw error;
1738
1753
  });
1739
1754
  }
@@ -2013,7 +2028,6 @@ export class Container
2013
2028
  { messageType: type },
2014
2029
  );
2015
2030
  this.close(newError);
2016
- this.dispose?.(newError);
2017
2031
  return -1;
2018
2032
  }
2019
2033
  }
@@ -2183,7 +2197,8 @@ export class Container
2183
2197
 
2184
2198
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
2185
2199
  // are set. Global requests will still go directly to the loader
2186
- const loader = new RelativeLoader(this, this.loader);
2200
+ const maybeLoader: FluidObject<IHostLoader> = this.scope;
2201
+ const loader = new RelativeLoader(this, maybeLoader.ILoader);
2187
2202
  this._context = await ContainerContext.createOrLoad(
2188
2203
  this,
2189
2204
  this.scope,
@@ -2200,7 +2215,7 @@ export class Container
2200
2215
  (batch: IBatchMessage[], referenceSequenceNumber?: number) =>
2201
2216
  this.submitBatch(batch, referenceSequenceNumber),
2202
2217
  (message) => this.submitSignal(message),
2203
- (error?: ICriticalContainerError) => this.dispose?.(error),
2218
+ (error?: ICriticalContainerError) => this.dispose(error),
2204
2219
  (error?: ICriticalContainerError) => this.close(error),
2205
2220
  Container.version,
2206
2221
  (dirty: boolean) => this.updateDirtyContainerState(dirty),
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryLogger } from "@fluidframework/common-definitions";
6
+ import { ITelemetryLoggerExt, PerformanceEvent } from "@fluidframework/telemetry-utils";
7
7
  import { assert, LazyPromise, TypedEventEmitter } from "@fluidframework/common-utils";
8
8
  import {
9
9
  IAudience,
@@ -25,7 +25,6 @@ import {
25
25
  } from "@fluidframework/container-definitions";
26
26
  import { IRequest, IResponse, FluidObject } from "@fluidframework/core-interfaces";
27
27
  import { IDocumentStorageService } from "@fluidframework/driver-definitions";
28
- import { isFluidResolvedUrl } from "@fluidframework/driver-utils";
29
28
  import {
30
29
  IClientConfiguration,
31
30
  IClientDetails,
@@ -40,7 +39,6 @@ import {
40
39
  MessageType,
41
40
  ISummaryContent,
42
41
  } from "@fluidframework/protocol-definitions";
43
- import { PerformanceEvent } from "@fluidframework/telemetry-utils";
44
42
  import { UsageError } from "@fluidframework/container-utils";
45
43
  import { Container } from "./container";
46
44
 
@@ -101,7 +99,7 @@ export class ContainerContext implements IContainerContext {
101
99
  return context;
102
100
  }
103
101
 
104
- public readonly taggedLogger: ITelemetryLogger;
102
+ public readonly taggedLogger: ITelemetryLoggerExt;
105
103
  public readonly supportedFeatures: ReadonlyMap<string, unknown>;
106
104
 
107
105
  public get clientId(): string | undefined {
@@ -112,11 +110,7 @@ export class ContainerContext implements IContainerContext {
112
110
  * DISCLAIMER: this id is only for telemetry purposes. Not suitable for any other usages.
113
111
  */
114
112
  public get id(): string {
115
- const resolvedUrl = this.container.resolvedUrl;
116
- if (isFluidResolvedUrl(resolvedUrl)) {
117
- return resolvedUrl.id;
118
- }
119
- return "";
113
+ return this.container.resolvedUrl?.id ?? "";
120
114
  }
121
115
 
122
116
  public get clientDetails(): IClientDetails {