@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/dist/container.js CHANGED
@@ -127,14 +127,11 @@ async function ReportIfTooLong(logger, eventName, action) {
127
127
  }
128
128
  exports.ReportIfTooLong = ReportIfTooLong;
129
129
  const summarizerClientType = "summarizer";
130
- /**
131
- * @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
132
- */
133
130
  class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
134
131
  /**
135
132
  * @internal
136
133
  */
137
- constructor(loader, config, protocolHandlerBuilder) {
134
+ constructor(createProps, loadProps) {
138
135
  var _a, _b, _c;
139
136
  super((name, error) => {
140
137
  this.mc.logger.sendErrorEvent({
@@ -142,8 +139,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
142
139
  name: typeof name === "string" ? name : undefined,
143
140
  }, error);
144
141
  });
145
- this.loader = loader;
146
- this.protocolHandlerBuilder = protocolHandlerBuilder;
142
+ this.createProps = createProps;
147
143
  // Tells if container can reconnect on losing fist connection
148
144
  // If false, container gets closed on loss of connection.
149
145
  this._canReconnect = true;
@@ -174,10 +170,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
174
170
  this.savedOps = [];
175
171
  this.setAutoReconnectTime = common_utils_1.performance.now();
176
172
  this._disposed = false;
177
- this.clientDetailsOverride = config.clientDetailsOverride;
178
- this._resolvedUrl = config.resolvedUrl;
179
- if (config.canReconnect !== undefined) {
180
- this._canReconnect = config.canReconnect;
173
+ this.clientDetailsOverride = createProps.clientDetailsOverride;
174
+ if (createProps.canReconnect !== undefined) {
175
+ this._canReconnect = createProps.canReconnect;
181
176
  }
182
177
  // Create logger for data stores to use
183
178
  const type = this.client.details.type;
@@ -185,15 +180,15 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
185
180
  const clientType = `${interactive ? "interactive" : "noninteractive"}${type !== undefined && type !== "" ? `/${type}` : ""}`;
186
181
  // Need to use the property getter for docId because for detached flow we don't have the docId initially.
187
182
  // We assign the id later so property getter is used.
188
- this.subLogger = telemetry_utils_1.ChildLogger.create(loader.services.subLogger, undefined, {
183
+ this.subLogger = telemetry_utils_1.ChildLogger.create(createProps.subLogger, undefined, {
189
184
  all: {
190
185
  clientType,
191
186
  containerId: (0, uuid_1.v4)(),
192
- docId: () => { var _a, _b; return (_b = (_a = this._resolvedUrl) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : undefined; },
187
+ docId: () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; },
193
188
  containerAttachState: () => this._attachState,
194
189
  containerLifecycleState: () => this._lifecycleState,
195
190
  containerConnectionState: () => connectionState_1.ConnectionState[this.connectionState],
196
- serializedContainer: config.serializedContainerState !== undefined,
191
+ serializedContainer: (loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState) !== undefined,
197
192
  },
198
193
  // we need to be judicious with our logging here to avoid generating too much data
199
194
  // all data logged here should be broadly applicable, and not specific to a
@@ -219,7 +214,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
219
214
  // Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
220
215
  // all clients that were loaded from the same loader (including summarizer clients).
221
216
  // Tracking alternative ways to handle this in AB#4129.
222
- this.options = Object.assign({}, this.loader.services.options);
217
+ this.options = Object.assign({}, this.createProps.options);
223
218
  this._deltaManager = this.createDeltaManager();
224
219
  this.connectionStateHandler = (0, connectionStateHandler_1.createConnectionStateHandler)({
225
220
  logger: this.mc.logger,
@@ -235,7 +230,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
235
230
  }
236
231
  },
237
232
  shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
238
- maxClientLeaveWaitTime: this.loader.services.options.maxClientLeaveWaitTime,
233
+ maxClientLeaveWaitTime: this.createProps.options.maxClientLeaveWaitTime,
239
234
  logConnectionIssue: (eventName, category, details) => {
240
235
  const mode = this.connectionMode;
241
236
  // We get here when socket does not receive any ops on "write" connection, including
@@ -259,7 +254,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
259
254
  this.connect();
260
255
  }
261
256
  },
262
- }, this.deltaManager, (_a = config.serializedContainerState) === null || _a === void 0 ? void 0 : _a.clientId);
257
+ }, this.deltaManager, (_a = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState) === null || _a === void 0 ? void 0 : _a.clientId);
263
258
  this.on(savedContainerEvent, () => {
264
259
  this.connectionStateHandler.containerSaved();
265
260
  });
@@ -271,8 +266,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
271
266
  : (0, driver_utils_1.combineAppAndProtocolSummary)(summaryTree, this.captureProtocolSummary());
272
267
  // Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
273
268
  // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
274
- const forceEnableSummarizeProtocolTree = (_b = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _b !== void 0 ? _b : this.loader.services.options.summarizeProtocolTree;
275
- this.storageAdapter = new containerStorageAdapter_1.ContainerStorageAdapter(this.loader.services.detachedBlobStorage, this.mc.logger, (_c = config.serializedContainerState) === null || _c === void 0 ? void 0 : _c.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
269
+ const forceEnableSummarizeProtocolTree = (_b = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _b !== void 0 ? _b : this.createProps.options.summarizeProtocolTree;
270
+ this.storageAdapter = new containerStorageAdapter_1.ContainerStorageAdapter(this.createProps.detachedBlobStorage, this.mc.logger, (_c = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState) === null || _c === void 0 ? void 0 : _c.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
276
271
  const isDomAvailable = typeof document === "object" &&
277
272
  document !== null &&
278
273
  typeof document.addEventListener === "function" &&
@@ -294,37 +289,34 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
294
289
  document.addEventListener("visibilitychange", this.visibilityEventHandler);
295
290
  }
296
291
  }
292
+ static async clone(container, loadProps, createParamOverrides) {
293
+ return this.load(loadProps, Object.assign(Object.assign({}, container.createProps), createParamOverrides));
294
+ }
297
295
  /**
298
296
  * Load an existing container.
299
297
  * @internal
300
298
  */
301
- static async load(loader, loadOptions, pendingLocalState, protocolHandlerBuilder) {
302
- const container = new Container(loader, {
303
- clientDetailsOverride: loadOptions.clientDetailsOverride,
304
- resolvedUrl: loadOptions.resolvedUrl,
305
- canReconnect: loadOptions.canReconnect,
306
- serializedContainerState: pendingLocalState,
307
- }, protocolHandlerBuilder);
299
+ static async load(loadProps, createProps) {
300
+ const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
301
+ const container = new Container(createProps, loadProps);
308
302
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
309
- var _a, _b;
310
- const version = loadOptions.version;
311
303
  const defaultMode = { opsBeforeReturn: "cached" };
312
304
  // if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
313
305
  // to return container, so ignore this value and use undefined for opsBeforeReturn
314
306
  const mode = pendingLocalState
315
- ? Object.assign(Object.assign({}, ((_a = loadOptions.loadMode) !== null && _a !== void 0 ? _a : defaultMode)), { opsBeforeReturn: undefined }) : (_b = loadOptions.loadMode) !== null && _b !== void 0 ? _b : defaultMode;
307
+ ? Object.assign(Object.assign({}, (loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode)), { opsBeforeReturn: undefined }) : loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode;
316
308
  const onClosed = (err) => {
317
309
  // pre-0.58 error message: containerClosedWithoutErrorDuringLoad
318
310
  reject(err !== null && err !== void 0 ? err : new container_utils_1.GenericError("Container closed without error during load"));
319
311
  };
320
312
  container.on("closed", onClosed);
321
313
  container
322
- .load(version, mode, pendingLocalState)
314
+ .load(version, mode, resolvedUrl, pendingLocalState)
323
315
  .finally(() => {
324
316
  container.removeListener("closed", onClosed);
325
317
  })
326
318
  .then((props) => {
327
- event.end(Object.assign(Object.assign({}, props), loadOptions.loadMode));
319
+ event.end(Object.assign(Object.assign({}, props), loadMode));
328
320
  resolve(container);
329
321
  }, (error) => {
330
322
  const err = (0, telemetry_utils_1.normalizeError)(error);
@@ -339,8 +331,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
339
331
  /**
340
332
  * Create a new container in a detached state.
341
333
  */
342
- static async createDetached(loader, codeDetails, protocolHandlerBuilder) {
343
- const container = new Container(loader, {}, protocolHandlerBuilder);
334
+ static async createDetached(createProps, codeDetails) {
335
+ const container = new Container(createProps);
344
336
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "CreateDetached" }, async (_event) => {
345
337
  await container.createDetached(codeDetails);
346
338
  return container;
@@ -350,8 +342,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
350
342
  * Create a new container in a detached state that is initialized with a
351
343
  * snapshot from a previous detached container.
352
344
  */
353
- static async rehydrateDetachedFromSnapshot(loader, snapshot, protocolHandlerBuilder) {
354
- const container = new Container(loader, {}, protocolHandlerBuilder);
345
+ static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
346
+ const container = new Container(createProps);
355
347
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
356
348
  const deserializedSummary = JSON.parse(snapshot);
357
349
  await container.rehydrateDetachedFromSnapshot(deserializedSummary);
@@ -395,7 +387,19 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
395
387
  return this;
396
388
  }
397
389
  get resolvedUrl() {
398
- return this._resolvedUrl;
390
+ var _a;
391
+ /**
392
+ * All attached containers will have a document service,
393
+ * this is required, as attached containers are attached to
394
+ * a service. Detached containers will neither have a document
395
+ * service or a resolved url as they only exist locally.
396
+ * in order to create a document service a resolved url must
397
+ * first be obtained, this is how the container is identified.
398
+ * Because of this, the document service's resolved url
399
+ * is always the same as the containers, as we had to
400
+ * obtain the resolved url, and then create the service from it.
401
+ */
402
+ return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
399
403
  }
400
404
  get loadedFromVersion() {
401
405
  return this._loadedFromVersion;
@@ -482,16 +486,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
482
486
  return this._dirtyContainer;
483
487
  }
484
488
  get serviceFactory() {
485
- return this.loader.services.documentServiceFactory;
489
+ return this.createProps.documentServiceFactory;
486
490
  }
487
491
  get urlResolver() {
488
- return this.loader.services.urlResolver;
492
+ return this.createProps.urlResolver;
489
493
  }
490
494
  get scope() {
491
- return this.loader.services.scope;
495
+ return this.createProps.scope;
492
496
  }
493
497
  get codeLoader() {
494
- return this.loader.services.codeLoader;
498
+ return this.createProps.codeLoader;
495
499
  }
496
500
  /**
497
501
  * {@inheritDoc @fluidframework/container-definitions#IContainer.entryPoint}
@@ -548,7 +552,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
548
552
  (0, common_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
549
553
  }
550
554
  closeCore(error) {
551
- var _a, _b, _c;
555
+ var _a;
552
556
  (0, common_utils_1.assert)(!this.closed, 0x315 /* re-entrancy */);
553
557
  try {
554
558
  // Ensure that we raise all key events even if one of these throws
@@ -566,12 +570,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
566
570
  this._lifecycleState = "closing";
567
571
  (_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
568
572
  this.connectionStateHandler.dispose();
569
- (_b = this._context) === null || _b === void 0 ? void 0 : _b.dispose(error !== undefined ? new Error(error.message) : undefined);
570
- this.storageAdapter.dispose();
571
- // Notify storage about critical errors. They may be due to disconnect between client & server knowledge
572
- // about file, like file being overwritten in storage, but client having stale local cache.
573
- // Driver need to ensure all caches are cleared on critical errors
574
- (_c = this.service) === null || _c === void 0 ? void 0 : _c.dispose(error);
575
573
  }
576
574
  catch (exception) {
577
575
  this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
@@ -660,8 +658,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
660
658
  const appSummary = this.context.createSummary();
661
659
  const protocolSummary = this.captureProtocolSummary();
662
660
  const combinedSummary = (0, driver_utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
663
- if (this.loader.services.detachedBlobStorage &&
664
- this.loader.services.detachedBlobStorage.size > 0) {
661
+ if (this.createProps.detachedBlobStorage && this.createProps.detachedBlobStorage.size > 0) {
665
662
  combinedSummary.tree[".hasAttachmentBlobs"] = {
666
663
  type: protocol_definitions_1.SummaryType.Blob,
667
664
  content: "true",
@@ -680,8 +677,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
680
677
  (0, common_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
681
678
  this.attachStarted = true;
682
679
  // If attachment blobs were uploaded in detached state we will go through a different attach flow
683
- const hasAttachmentBlobs = this.loader.services.detachedBlobStorage !== undefined &&
684
- this.loader.services.detachedBlobStorage.size > 0;
680
+ const hasAttachmentBlobs = this.createProps.detachedBlobStorage !== undefined &&
681
+ this.createProps.detachedBlobStorage.size > 0;
685
682
  try {
686
683
  (0, common_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
687
684
  let summary;
@@ -705,31 +702,28 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
705
702
  }
706
703
  }
707
704
  // Actually go and create the resolved document
708
- const createNewResolvedUrl = await this.urlResolver.resolve(request);
709
- (0, driver_utils_1.ensureFluidResolvedUrl)(createNewResolvedUrl);
710
705
  if (this.service === undefined) {
711
- (0, common_utils_1.assert)(this.client.details.type !== summarizerClientType, 0x2c4 /* "client should not be summarizer before container is created" */);
706
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
707
+ (0, common_utils_1.assert)(this.client.details.type !== summarizerClientType &&
708
+ createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
712
709
  this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
713
710
  cancel: this.closeSignal,
714
711
  });
715
712
  }
716
- const resolvedUrl = this.service.resolvedUrl;
717
- (0, driver_utils_1.ensureFluidResolvedUrl)(resolvedUrl);
718
- this._resolvedUrl = resolvedUrl;
719
713
  await this.storageAdapter.connectToService(this.service);
720
714
  if (hasAttachmentBlobs) {
721
715
  // upload blobs to storage
722
- (0, common_utils_1.assert)(!!this.loader.services.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
716
+ (0, common_utils_1.assert)(!!this.createProps.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
723
717
  // build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
724
718
  // support blob handles that only know about the local IDs
725
719
  const redirectTable = new Map();
726
720
  // if new blobs are added while uploading, upload them too
727
- while (redirectTable.size < this.loader.services.detachedBlobStorage.size) {
728
- const newIds = this.loader.services.detachedBlobStorage
721
+ while (redirectTable.size < this.createProps.detachedBlobStorage.size) {
722
+ const newIds = this.createProps.detachedBlobStorage
729
723
  .getBlobIds()
730
724
  .filter((id) => !redirectTable.has(id));
731
725
  for (const id of newIds) {
732
- const blob = await this.loader.services.detachedBlobStorage.readBlob(id);
726
+ const blob = await this.createProps.detachedBlobStorage.readBlob(id);
733
727
  const response = await this.storageAdapter.createBlob(blob);
734
728
  redirectTable.set(id, response.id);
735
729
  }
@@ -764,12 +758,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
764
758
  catch (error) {
765
759
  // add resolved URL on error object so that host has the ability to find this document and delete it
766
760
  const newError = (0, telemetry_utils_1.normalizeError)(error);
767
- const resolvedUrl = this.resolvedUrl;
768
- if ((0, driver_utils_1.isFluidResolvedUrl)(resolvedUrl)) {
769
- newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
770
- }
761
+ newError.addTelemetryProperties({ resolvedUrl: (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.url });
771
762
  this.close(newError);
772
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
773
763
  throw newError;
774
764
  }
775
765
  }, { start: true, end: true, cancel: "generic" });
@@ -864,7 +854,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
864
854
  .catch(() => false);
865
855
  }
866
856
  async processCodeProposal() {
867
- var _a;
868
857
  const codeDetails = this.getCodeDetailsFromQuorum();
869
858
  await Promise.all([
870
859
  this.deltaManager.inbound.pause(),
@@ -878,7 +867,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
878
867
  // pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
879
868
  const error = new container_utils_1.GenericError("Existing context does not satisfy incoming proposal");
880
869
  this.close(error);
881
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
882
870
  }
883
871
  async getVersion(version) {
884
872
  const versions = await this.storageAdapter.getVersions(version, 1);
@@ -902,12 +890,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
902
890
  *
903
891
  * @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
904
892
  */
905
- async load(specifiedVersion, loadMode, pendingLocalState) {
893
+ async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
906
894
  var _a;
907
- if (this._resolvedUrl === undefined) {
908
- throw new Error("Attempting to load without a resolved url");
909
- }
910
- this.service = await this.serviceFactory.createDocumentService(this._resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
895
+ this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
911
896
  // Ideally we always connect as "read" by default.
912
897
  // Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
913
898
  // We should not rely on it by (one of them will address the issue, but we need to address both)
@@ -933,9 +918,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
933
918
  else {
934
919
  // if we have pendingLocalState we can load without storage; don't wait for connection
935
920
  this.storageAdapter.connectToService(this.service).catch((error) => {
936
- var _a;
937
921
  this.close(error);
938
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
939
922
  });
940
923
  }
941
924
  this._attachState = container_definitions_1.AttachState.Attached;
@@ -1061,8 +1044,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1061
1044
  }
1062
1045
  async rehydrateDetachedFromSnapshot(detachedContainerSnapshot) {
1063
1046
  if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
1064
- (0, common_utils_1.assert)(!!this.loader.services.detachedBlobStorage &&
1065
- this.loader.services.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1047
+ (0, common_utils_1.assert)(!!this.createProps.detachedBlobStorage &&
1048
+ this.createProps.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1066
1049
  delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
1067
1050
  }
1068
1051
  const snapshotTree = (0, utils_1.getSnapshotTreeFromSerializedContainer)(detachedContainerSnapshot);
@@ -1116,7 +1099,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1116
1099
  }
1117
1100
  initializeProtocolState(attributes, quorumSnapshot) {
1118
1101
  var _a;
1119
- const protocolHandlerBuilder = (_a = this.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
1102
+ const protocolHandlerBuilder = (_a = this.createProps.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
1120
1103
  const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, JSON.stringify({ key, value })));
1121
1104
  const protocolLogger = telemetry_utils_1.ChildLogger.create(this.subLogger, "ProtocolHandler");
1122
1105
  protocol.quorum.on("error", (error) => {
@@ -1137,10 +1120,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1137
1120
  });
1138
1121
  }
1139
1122
  this.processCodeProposal().catch((error) => {
1140
- var _a;
1141
1123
  const normalizedError = (0, telemetry_utils_1.normalizeError)(error);
1142
1124
  this.close(normalizedError);
1143
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, normalizedError);
1144
1125
  throw error;
1145
1126
  });
1146
1127
  }
@@ -1330,7 +1311,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1330
1311
  }
1331
1312
  // back-compat: ADO #1385: Remove in the future, summary op should come through submitSummaryMessage()
1332
1313
  submitContainerMessage(type, contents, batch, metadata) {
1333
- var _a;
1334
1314
  switch (type) {
1335
1315
  case protocol_definitions_1.MessageType.Operation:
1336
1316
  return this.submitMessage(type, JSON.stringify(contents), batch, metadata);
@@ -1339,7 +1319,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1339
1319
  default: {
1340
1320
  const newError = new container_utils_1.GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type });
1341
1321
  this.close(newError);
1342
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
1343
1322
  return -1;
1344
1323
  }
1345
1324
  }
@@ -1448,8 +1427,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1448
1427
  (0, common_utils_1.assert)(((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing context not disposed" */);
1449
1428
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
1450
1429
  // are set. Global requests will still go directly to the loader
1451
- const loader = new loader_1.RelativeLoader(this, this.loader);
1452
- this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => { var _a; return (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error); }, (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
1430
+ const maybeLoader = this.scope;
1431
+ const loader = new loader_1.RelativeLoader(this, maybeLoader.ILoader);
1432
+ this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => this.dispose(error), (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
1453
1433
  this.emit("contextChanged", codeDetails);
1454
1434
  }
1455
1435
  updateDirtyContainerState(dirty) {