@fluidframework/container-loader 2.0.0-internal.5.1.1 → 2.0.0-internal.5.3.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 (145) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/catchUpMonitor.d.ts +1 -1
  3. package/dist/catchUpMonitor.d.ts.map +1 -1
  4. package/dist/catchUpMonitor.js.map +1 -1
  5. package/dist/connectionManager.d.ts +1 -1
  6. package/dist/connectionManager.d.ts.map +1 -1
  7. package/dist/connectionManager.js.map +1 -1
  8. package/dist/connectionStateHandler.d.ts +4 -1
  9. package/dist/connectionStateHandler.d.ts.map +1 -1
  10. package/dist/connectionStateHandler.js +10 -8
  11. package/dist/connectionStateHandler.js.map +1 -1
  12. package/dist/container.d.ts +30 -31
  13. package/dist/container.d.ts.map +1 -1
  14. package/dist/container.js +182 -109
  15. package/dist/container.js.map +1 -1
  16. package/dist/containerContext.d.ts +23 -66
  17. package/dist/containerContext.d.ts.map +1 -1
  18. package/dist/containerContext.js +28 -213
  19. package/dist/containerContext.js.map +1 -1
  20. package/dist/containerStorageAdapter.d.ts +1 -1
  21. package/dist/containerStorageAdapter.d.ts.map +1 -1
  22. package/dist/containerStorageAdapter.js +38 -6
  23. package/dist/containerStorageAdapter.js.map +1 -1
  24. package/dist/contracts.d.ts +1 -3
  25. package/dist/contracts.d.ts.map +1 -1
  26. package/dist/contracts.js.map +1 -1
  27. package/dist/deltaManager.d.ts +2 -1
  28. package/dist/deltaManager.d.ts.map +1 -1
  29. package/dist/deltaManager.js.map +1 -1
  30. package/dist/disposal.d.ts +13 -0
  31. package/dist/disposal.d.ts.map +1 -0
  32. package/dist/disposal.js +25 -0
  33. package/dist/disposal.js.map +1 -0
  34. package/dist/loader.d.ts +1 -2
  35. package/dist/loader.d.ts.map +1 -1
  36. package/dist/loader.js.map +1 -1
  37. package/dist/noopHeuristic.d.ts +23 -0
  38. package/dist/noopHeuristic.d.ts.map +1 -0
  39. package/dist/{collabWindowTracker.js → noopHeuristic.js} +30 -42
  40. package/dist/noopHeuristic.js.map +1 -0
  41. package/dist/packageVersion.d.ts +1 -1
  42. package/dist/packageVersion.js +1 -1
  43. package/dist/packageVersion.js.map +1 -1
  44. package/dist/protocol.d.ts +7 -12
  45. package/dist/protocol.d.ts.map +1 -1
  46. package/dist/protocol.js +17 -19
  47. package/dist/protocol.js.map +1 -1
  48. package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
  49. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  50. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  51. package/dist/quorum.d.ts +1 -17
  52. package/dist/quorum.d.ts.map +1 -1
  53. package/dist/quorum.js +1 -17
  54. package/dist/quorum.js.map +1 -1
  55. package/dist/retriableDocumentStorageService.d.ts +1 -1
  56. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  57. package/dist/retriableDocumentStorageService.js.map +1 -1
  58. package/lib/catchUpMonitor.d.ts +1 -1
  59. package/lib/catchUpMonitor.d.ts.map +1 -1
  60. package/lib/catchUpMonitor.js.map +1 -1
  61. package/lib/connectionManager.d.ts +1 -1
  62. package/lib/connectionManager.d.ts.map +1 -1
  63. package/lib/connectionManager.js.map +1 -1
  64. package/lib/connectionStateHandler.d.ts +4 -1
  65. package/lib/connectionStateHandler.d.ts.map +1 -1
  66. package/lib/connectionStateHandler.js +10 -8
  67. package/lib/connectionStateHandler.js.map +1 -1
  68. package/lib/container.d.ts +30 -31
  69. package/lib/container.d.ts.map +1 -1
  70. package/lib/container.js +186 -113
  71. package/lib/container.js.map +1 -1
  72. package/lib/containerContext.d.ts +23 -66
  73. package/lib/containerContext.d.ts.map +1 -1
  74. package/lib/containerContext.js +28 -213
  75. package/lib/containerContext.js.map +1 -1
  76. package/lib/containerStorageAdapter.d.ts +1 -1
  77. package/lib/containerStorageAdapter.d.ts.map +1 -1
  78. package/lib/containerStorageAdapter.js +38 -6
  79. package/lib/containerStorageAdapter.js.map +1 -1
  80. package/lib/contracts.d.ts +1 -3
  81. package/lib/contracts.d.ts.map +1 -1
  82. package/lib/contracts.js.map +1 -1
  83. package/lib/deltaManager.d.ts +2 -1
  84. package/lib/deltaManager.d.ts.map +1 -1
  85. package/lib/deltaManager.js.map +1 -1
  86. package/lib/disposal.d.ts +13 -0
  87. package/lib/disposal.d.ts.map +1 -0
  88. package/lib/disposal.js +21 -0
  89. package/lib/disposal.js.map +1 -0
  90. package/lib/loader.d.ts +1 -2
  91. package/lib/loader.d.ts.map +1 -1
  92. package/lib/loader.js.map +1 -1
  93. package/lib/noopHeuristic.d.ts +23 -0
  94. package/lib/noopHeuristic.d.ts.map +1 -0
  95. package/lib/{collabWindowTracker.js → noopHeuristic.js} +30 -42
  96. package/lib/noopHeuristic.js.map +1 -0
  97. package/lib/packageVersion.d.ts +1 -1
  98. package/lib/packageVersion.js +1 -1
  99. package/lib/packageVersion.js.map +1 -1
  100. package/lib/protocol.d.ts +7 -12
  101. package/lib/protocol.d.ts.map +1 -1
  102. package/lib/protocol.js +15 -18
  103. package/lib/protocol.js.map +1 -1
  104. package/lib/protocolTreeDocumentStorageService.d.ts +1 -1
  105. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  106. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  107. package/lib/quorum.d.ts +1 -17
  108. package/lib/quorum.d.ts.map +1 -1
  109. package/lib/quorum.js +1 -16
  110. package/lib/quorum.js.map +1 -1
  111. package/lib/retriableDocumentStorageService.d.ts +1 -1
  112. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  113. package/lib/retriableDocumentStorageService.js.map +1 -1
  114. package/package.json +18 -14
  115. package/src/catchUpMonitor.ts +1 -1
  116. package/src/connectionManager.ts +1 -1
  117. package/src/connectionStateHandler.ts +15 -10
  118. package/src/container.ts +284 -139
  119. package/src/containerContext.ts +33 -335
  120. package/src/containerStorageAdapter.ts +47 -5
  121. package/src/contracts.ts +1 -3
  122. package/src/deltaManager.ts +15 -8
  123. package/src/disposal.ts +25 -0
  124. package/src/loader.ts +1 -1
  125. package/src/{collabWindowTracker.ts → noopHeuristic.ts} +37 -47
  126. package/src/packageVersion.ts +1 -1
  127. package/src/protocol.ts +18 -39
  128. package/src/protocolTreeDocumentStorageService.ts +1 -1
  129. package/src/quorum.ts +2 -31
  130. package/src/retriableDocumentStorageService.ts +2 -1
  131. package/dist/collabWindowTracker.d.ts +0 -19
  132. package/dist/collabWindowTracker.d.ts.map +0 -1
  133. package/dist/collabWindowTracker.js.map +0 -1
  134. package/dist/deltaManagerProxy.d.ts +0 -42
  135. package/dist/deltaManagerProxy.d.ts.map +0 -1
  136. package/dist/deltaManagerProxy.js +0 -79
  137. package/dist/deltaManagerProxy.js.map +0 -1
  138. package/lib/collabWindowTracker.d.ts +0 -19
  139. package/lib/collabWindowTracker.d.ts.map +0 -1
  140. package/lib/collabWindowTracker.js.map +0 -1
  141. package/lib/deltaManagerProxy.d.ts +0 -42
  142. package/lib/deltaManagerProxy.d.ts.map +0 -1
  143. package/lib/deltaManagerProxy.js +0 -74
  144. package/lib/deltaManagerProxy.js.map +0 -1
  145. package/src/deltaManagerProxy.ts +0 -109
package/dist/container.js CHANGED
@@ -21,20 +21,20 @@ const audience_1 = require("./audience");
21
21
  const containerContext_1 = require("./containerContext");
22
22
  const contracts_1 = require("./contracts");
23
23
  const deltaManager_1 = require("./deltaManager");
24
- const deltaManagerProxy_1 = require("./deltaManagerProxy");
25
24
  const loader_1 = require("./loader");
26
25
  const packageVersion_1 = require("./packageVersion");
27
26
  const containerStorageAdapter_1 = require("./containerStorageAdapter");
28
27
  const connectionStateHandler_1 = require("./connectionStateHandler");
29
28
  const utils_1 = require("./utils");
30
29
  const quorum_1 = require("./quorum");
31
- const collabWindowTracker_1 = require("./collabWindowTracker");
30
+ const noopHeuristic_1 = require("./noopHeuristic");
32
31
  const connectionManager_1 = require("./connectionManager");
33
32
  const connectionState_1 = require("./connectionState");
34
33
  const protocol_1 = require("./protocol");
35
34
  const detachedContainerRefSeqNumber = 0;
36
35
  const dirtyContainerEvent = "dirty";
37
36
  const savedContainerEvent = "saved";
37
+ const packageNotFactoryError = "Code package does not implement IRuntimeFactory";
38
38
  /**
39
39
  * Waits until container connects to delta storage and gets up-to-date.
40
40
  *
@@ -164,8 +164,23 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
164
164
  this.attachStarted = false;
165
165
  this._dirtyContainer = false;
166
166
  this.savedOps = [];
167
+ this.clientsWhoShouldHaveLeft = new Set();
167
168
  this.setAutoReconnectTime = common_utils_1.performance.now();
169
+ this._lifecycleEvents = new common_utils_1.TypedEventEmitter();
168
170
  this._disposed = false;
171
+ this.getAbsoluteUrl = async (relativeUrl) => {
172
+ if (this.resolvedUrl === undefined) {
173
+ return undefined;
174
+ }
175
+ return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0, contracts_1.getPackageName)(this._loadedCodeDetails));
176
+ };
177
+ this.updateDirtyContainerState = (dirty) => {
178
+ if (this._dirtyContainer === dirty) {
179
+ return;
180
+ }
181
+ this._dirtyContainer = dirty;
182
+ this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
183
+ };
169
184
  const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
170
185
  this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = common_utils_1.performance.now();
171
186
  const pendingLocalState = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState;
@@ -210,13 +225,18 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
210
225
  dmInitialSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.initialSequenceNumber; },
211
226
  dmLastProcessedSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.lastSequenceNumber; },
212
227
  dmLastKnownSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.lastKnownSeqNumber; },
213
- containerLoadedFromVersionId: () => { var _a; return (_a = this.loadedFromVersion) === null || _a === void 0 ? void 0 : _a.id; },
214
- containerLoadedFromVersionDate: () => { var _a; return (_a = this.loadedFromVersion) === null || _a === void 0 ? void 0 : _a.date; },
228
+ containerLoadedFromVersionId: () => { var _a; return (_a = this._loadedFromVersion) === null || _a === void 0 ? void 0 : _a.id; },
229
+ containerLoadedFromVersionDate: () => { var _a; return (_a = this._loadedFromVersion) === null || _a === void 0 ? void 0 : _a.date; },
215
230
  // message information to associate errors with the specific execution state
216
231
  // dmLastMsqSeqNumber: if present, same as dmLastProcessedSeqNumber
217
232
  dmLastMsqSeqNumber: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.sequenceNumber; },
218
233
  dmLastMsqSeqTimestamp: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.timestamp; },
219
- dmLastMsqSeqClientId: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientId; },
234
+ dmLastMsqSeqClientId: () => {
235
+ var _a, _b, _c, _d;
236
+ return ((_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientId) === null
237
+ ? "null"
238
+ : (_d = (_c = this.deltaManager) === null || _c === void 0 ? void 0 : _c.lastMessage) === null || _d === void 0 ? void 0 : _d.clientId;
239
+ },
220
240
  dmLastMsgClientSeq: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientSequenceNumber; },
221
241
  connectionStateDuration: () => common_utils_1.performance.now() - this.connectionTransitionTimes[this.connectionState],
222
242
  },
@@ -262,6 +282,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
262
282
  this.connect();
263
283
  }
264
284
  },
285
+ clientShouldHaveLeft: (clientId) => {
286
+ this.clientsWhoShouldHaveLeft.add(clientId);
287
+ },
265
288
  }, this.deltaManager, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.clientId);
266
289
  this.on(savedContainerEvent, () => {
267
290
  this.connectionStateHandler.containerSaved();
@@ -304,6 +327,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
304
327
  static async load(loadProps, createProps) {
305
328
  const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
306
329
  const container = new Container(createProps, loadProps);
330
+ const disableRecordHeapSize = container.mc.config.getBoolean("Fluid.Loader.DisableRecordHeapSize");
307
331
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
308
332
  const defaultMode = { opsBeforeReturn: "cached" };
309
333
  // if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
@@ -331,7 +355,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
331
355
  container.close(err);
332
356
  onClosed(err);
333
357
  });
334
- }), { start: true, end: true, cancel: "generic" });
358
+ }), { start: true, end: true, cancel: "generic" }, disableRecordHeapSize !== true /* recordHeapSize */);
335
359
  }
336
360
  /**
337
361
  * Create a new container in a detached state.
@@ -370,14 +394,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
370
394
  this._lifecycleState === "disposing" ||
371
395
  this._lifecycleState === "disposed");
372
396
  }
373
- get storage() {
374
- return this.storageAdapter;
375
- }
376
- get context() {
377
- if (this._context === undefined) {
378
- throw new container_utils_1.GenericError("Attempted to access context before it was defined");
397
+ get runtime() {
398
+ if (this._runtime === undefined) {
399
+ throw new Error("Attempted to access runtime before it was defined");
379
400
  }
380
- return this._context;
401
+ return this._runtime;
381
402
  }
382
403
  get protocolHandler() {
383
404
  if (this._protocolHandler === undefined) {
@@ -406,15 +427,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
406
427
  */
407
428
  return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
408
429
  }
409
- get loadedFromVersion() {
410
- return this._loadedFromVersion;
411
- }
412
430
  get readOnlyInfo() {
413
431
  return this._deltaManager.readOnlyInfo;
414
432
  }
415
- get closeSignal() {
416
- return this._deltaManager.closeAbortController.signal;
417
- }
418
433
  /**
419
434
  * Tracks host requiring read-only mode.
420
435
  */
@@ -430,13 +445,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
430
445
  get connected() {
431
446
  return this.connectionStateHandler.connectionState === connectionState_1.ConnectionState.Connected;
432
447
  }
433
- /**
434
- * Service configuration details. If running in offline mode will be undefined otherwise will contain service
435
- * configuration details returned as part of the initial connection.
436
- */
437
- get serviceConfiguration() {
438
- return this._deltaManager.serviceConfiguration;
439
- }
440
448
  /**
441
449
  * The server provided id of the client.
442
450
  * Set once this.connected is true, otherwise undefined
@@ -444,21 +452,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
444
452
  get clientId() {
445
453
  return this._clientId;
446
454
  }
447
- /**
448
- * The server provided claims of the client.
449
- * Set once this.connected is true, otherwise undefined
450
- */
451
- get scopes() {
452
- return this._deltaManager.connectionManager.scopes;
453
- }
454
- get clientDetails() {
455
- return this._deltaManager.clientDetails;
456
- }
457
455
  get offlineLoadEnabled() {
458
456
  var _a, _b;
459
457
  const enabled = (_a = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) !== null && _a !== void 0 ? _a : ((_b = this.options) === null || _b === void 0 ? void 0 : _b.enableOfflineLoad) === true;
460
458
  // summarizer will not have any pending state we want to save
461
- return enabled && this.clientDetails.capabilities.interactive;
459
+ return enabled && this.deltaManager.clientDetails.capabilities.interactive;
462
460
  }
463
461
  /**
464
462
  * Get the code details that are currently specified for the container.
@@ -473,8 +471,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
473
471
  * loaded.
474
472
  */
475
473
  getLoadedCodeDetails() {
476
- var _a;
477
- return (_a = this._context) === null || _a === void 0 ? void 0 : _a.codeDetails;
474
+ return this._loadedCodeDetails;
478
475
  }
479
476
  /**
480
477
  * Retrieves the audience associated with the document
@@ -495,32 +492,26 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
495
492
  */
496
493
  async getEntryPoint() {
497
494
  var _a, _b;
498
- // Only the disposing/disposed lifecycle states should prevent access to the entryPoint; closing/closed should still
499
- // allow it since they mean a kind of read-only state for the Container.
500
- // Note that all 4 are lifecycle states but only 'closed' and 'disposed' are emitted as events.
501
- if (this._lifecycleState === "disposing" || this._lifecycleState === "disposed") {
502
- throw new container_utils_1.UsageError("The container is disposing or disposed");
503
- }
504
- while (this._context === undefined) {
505
- await new Promise((resolve, reject) => {
506
- const contextChangedHandler = () => {
507
- resolve();
508
- this.off("disposed", disposedHandler);
509
- };
510
- const disposedHandler = (error) => {
511
- reject(error !== null && error !== void 0 ? error : "The Container is disposed");
512
- this.off("contextChanged", contextChangedHandler);
513
- };
514
- this.once("contextChanged", contextChangedHandler);
515
- this.once("disposed", disposedHandler);
516
- });
517
- // The Promise above should only resolve (vs reject) if the 'contextChanged' event was emitted and that
518
- // should have set this._context; making sure.
519
- (0, common_utils_1.assert)(this._context !== undefined, 0x5a2 /* Context still not defined after contextChanged event */);
495
+ if (this._disposed) {
496
+ throw new container_utils_1.UsageError("The context is already disposed");
497
+ }
498
+ if (this._runtime !== undefined) {
499
+ return (_b = (_a = this._runtime).getEntryPoint) === null || _b === void 0 ? void 0 : _b.call(_a);
520
500
  }
521
- // Disable lint rule for the sake of more complete stack traces
522
- // eslint-disable-next-line no-return-await
523
- return await ((_b = (_a = this._context).getEntryPoint) === null || _b === void 0 ? void 0 : _b.call(_a));
501
+ return new Promise((resolve, reject) => {
502
+ const runtimeInstantiatedHandler = () => {
503
+ var _a, _b;
504
+ (0, common_utils_1.assert)(this._runtime !== undefined, 0x5a3 /* runtimeInstantiated fired but runtime is still undefined */);
505
+ resolve((_b = (_a = this._runtime).getEntryPoint) === null || _b === void 0 ? void 0 : _b.call(_a));
506
+ this._lifecycleEvents.off("disposed", disposedHandler);
507
+ };
508
+ const disposedHandler = () => {
509
+ reject(new Error("ContainerContext was disposed"));
510
+ this._lifecycleEvents.off("runtimeInstantiated", runtimeInstantiatedHandler);
511
+ };
512
+ this._lifecycleEvents.once("runtimeInstantiated", runtimeInstantiatedHandler);
513
+ this._lifecycleEvents.once("disposed", disposedHandler);
514
+ });
524
515
  }
525
516
  /**
526
517
  * Retrieves the quorum associated with the document
@@ -574,6 +565,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
574
565
  }
575
566
  finally {
576
567
  this._lifecycleState = "closed";
568
+ // There is no user for summarizer, so we need to ensure dispose is called
569
+ if (this.client.details.type === summarizerClientType) {
570
+ this.dispose(error);
571
+ }
577
572
  }
578
573
  }
579
574
  disposeCore(error) {
@@ -587,7 +582,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
587
582
  // This gives us a chance to know what errors happened on open vs. on fully loaded container.
588
583
  this.mc.logger.sendTelemetryEvent({
589
584
  eventName: "ContainerDispose",
590
- category: "generic",
585
+ // Only log error if container isn't closed
586
+ category: !this.closed && error !== undefined ? "error" : "generic",
591
587
  }, error);
592
588
  // ! Progressing from "closed" to "disposing" is not allowed
593
589
  if (this._lifecycleState !== "closed") {
@@ -595,7 +591,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
595
591
  }
596
592
  (_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
597
593
  this.connectionStateHandler.dispose();
598
- (_b = this._context) === null || _b === void 0 ? void 0 : _b.dispose(error !== undefined ? new Error(error.message) : undefined);
594
+ const maybeError = error !== undefined ? new Error(error.message) : undefined;
595
+ (_b = this._runtime) === null || _b === void 0 ? void 0 : _b.dispose(maybeError);
599
596
  this.storageAdapter.dispose();
600
597
  // Notify storage about critical errors. They may be due to disconnect between client & server knowledge
601
598
  // about file, like file being overwritten in storage, but client having stale local cache.
@@ -613,6 +610,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
613
610
  }
614
611
  finally {
615
612
  this._lifecycleState = "disposed";
613
+ this._lifecycleEvents.emit("disposed");
616
614
  }
617
615
  }
618
616
  closeAndGetPendingLocalState() {
@@ -627,12 +625,15 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
627
625
  if (!this.offlineLoadEnabled) {
628
626
  throw new container_utils_1.UsageError("Can't get pending local state unless offline load is enabled");
629
627
  }
628
+ if (this.closed || this._disposed) {
629
+ throw new container_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
630
+ }
630
631
  (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
631
632
  (0, common_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
632
633
  (0, common_utils_1.assert)(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
633
634
  (0, common_utils_1.assert)(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
634
635
  const pendingState = {
635
- pendingRuntimeState: this.context.getPendingLocalState(),
636
+ pendingRuntimeState: this.runtime.getPendingLocalState(),
636
637
  baseSnapshot: this.baseSnapshot,
637
638
  snapshotBlobs: this.baseSnapshotBlobs,
638
639
  savedOps: this.savedOps,
@@ -648,7 +649,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
648
649
  }
649
650
  serialize() {
650
651
  (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Detached, 0x0d3 /* "Should only be called in detached container" */);
651
- const appSummary = this.context.createSummary();
652
+ const appSummary = this.runtime.createSummary();
652
653
  const protocolSummary = this.captureProtocolSummary();
653
654
  const combinedSummary = (0, driver_utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
654
655
  if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
@@ -677,7 +678,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
677
678
  if (!hasAttachmentBlobs) {
678
679
  // Get the document state post attach - possibly can just call attach but we need to change the
679
680
  // semantics around what the attach means as far as async code goes.
680
- const appSummary = this.context.createSummary();
681
+ const appSummary = this.runtime.createSummary();
681
682
  const protocolSummary = this.captureProtocolSummary();
682
683
  summary = (0, driver_utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
683
684
  // Set the state as attaching as we are starting the process of attaching container.
@@ -685,6 +686,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
685
686
  // starting to attach the container to storage.
686
687
  // Also, this should only be fired in detached container.
687
688
  this._attachState = container_definitions_1.AttachState.Attaching;
689
+ this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
688
690
  this.emit("attaching");
689
691
  if (this.offlineLoadEnabled) {
690
692
  const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
@@ -699,7 +701,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
699
701
  (0, common_utils_1.assert)(this.client.details.type !== summarizerClientType &&
700
702
  createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
701
703
  this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
702
- cancel: this.closeSignal,
704
+ cancel: this._deltaManager.closeAbortController.signal,
703
705
  });
704
706
  }
705
707
  await this.storageAdapter.connectToService(this.service);
@@ -721,10 +723,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
721
723
  }
722
724
  }
723
725
  // take summary and upload
724
- const appSummary = this.context.createSummary(redirectTable);
726
+ const appSummary = this.runtime.createSummary(redirectTable);
725
727
  const protocolSummary = this.captureProtocolSummary();
726
728
  summary = (0, driver_utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
727
729
  this._attachState = container_definitions_1.AttachState.Attaching;
730
+ this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
728
731
  this.emit("attaching");
729
732
  if (this.offlineLoadEnabled) {
730
733
  const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
@@ -739,6 +742,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
739
742
  });
740
743
  }
741
744
  this._attachState = container_definitions_1.AttachState.Attached;
745
+ this.runtime.setAttachState(container_definitions_1.AttachState.Attached);
742
746
  this.emit("attached");
743
747
  if (!this.closed) {
744
748
  this.resumeInternal({
@@ -757,7 +761,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
757
761
  }, { start: true, end: true, cancel: "generic" });
758
762
  }
759
763
  async request(path) {
760
- return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Request" }, async () => this.context.request(path), { end: true, cancel: "error" });
764
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Request" }, async () => this.runtime.request(path), { end: true, cancel: "error" });
761
765
  }
762
766
  setAutoReconnectInternal(mode) {
763
767
  const currentMode = this._deltaManager.connectionManager.reconnectMode;
@@ -823,13 +827,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
823
827
  // Ensure connection to web socket
824
828
  this.connectToDeltaStream(args);
825
829
  }
826
- async getAbsoluteUrl(relativeUrl) {
827
- var _a;
828
- if (this.resolvedUrl === undefined) {
829
- return undefined;
830
- }
831
- return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0, contracts_1.getPackageName)((_a = this._context) === null || _a === void 0 ? void 0 : _a.codeDetails));
832
- }
833
830
  async proposeCodeDetails(codeDetails) {
834
831
  if (!(0, container_definitions_1.isFluidCodeDetails)(codeDetails)) {
835
832
  throw new Error("Provided codeDetails are not IFluidCodeDetails");
@@ -851,7 +848,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
851
848
  this.deltaManager.inbound.pause(),
852
849
  this.deltaManager.inboundSignal.pause(),
853
850
  ]);
854
- if ((await this.context.satisfies(codeDetails)) === true) {
851
+ if ((await this.satisfies(codeDetails)) === true) {
855
852
  this.deltaManager.inbound.resume();
856
853
  this.deltaManager.inboundSignal.resume();
857
854
  return;
@@ -860,6 +857,38 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
860
857
  const error = new container_utils_1.GenericError("Existing context does not satisfy incoming proposal");
861
858
  this.close(error);
862
859
  }
860
+ /**
861
+ * Determines if the currently loaded module satisfies the incoming constraint code details
862
+ */
863
+ async satisfies(constraintCodeDetails) {
864
+ var _a, _b;
865
+ // If we have no module, it can't satisfy anything.
866
+ if (this._loadedModule === undefined) {
867
+ return false;
868
+ }
869
+ const comparers = [];
870
+ const maybeCompareCodeLoader = this.codeLoader;
871
+ if (maybeCompareCodeLoader.IFluidCodeDetailsComparer !== undefined) {
872
+ comparers.push(maybeCompareCodeLoader.IFluidCodeDetailsComparer);
873
+ }
874
+ const maybeCompareExport = (_a = this._loadedModule) === null || _a === void 0 ? void 0 : _a.module.fluidExport;
875
+ if ((maybeCompareExport === null || maybeCompareExport === void 0 ? void 0 : maybeCompareExport.IFluidCodeDetailsComparer) !== undefined) {
876
+ comparers.push(maybeCompareExport.IFluidCodeDetailsComparer);
877
+ }
878
+ // If there are no comparers, then it's impossible to know if the currently loaded package satisfies
879
+ // the incoming constraint, so we return false. Assuming it does not satisfy is safer, to force a reload
880
+ // rather than potentially running with incompatible code.
881
+ if (comparers.length === 0) {
882
+ return false;
883
+ }
884
+ for (const comparer of comparers) {
885
+ const satisfies = await comparer.satisfies((_b = this._loadedModule) === null || _b === void 0 ? void 0 : _b.details, constraintCodeDetails);
886
+ if (satisfies === false) {
887
+ return false;
888
+ }
889
+ }
890
+ return true;
891
+ }
863
892
  async getVersion(version) {
864
893
  const versions = await this.storageAdapter.getVersions(version, 1);
865
894
  return versions[0];
@@ -877,7 +906,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
877
906
  * @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
878
907
  */
879
908
  async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
880
- var _a;
909
+ var _a, _b, _c;
881
910
  this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
882
911
  // Ideally we always connect as "read" by default.
883
912
  // Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
@@ -921,7 +950,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
921
950
  if (this.offlineLoadEnabled) {
922
951
  this.baseSnapshot = snapshot;
923
952
  // Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
924
- this.baseSnapshotBlobs = await (0, containerStorageAdapter_1.getBlobContentsFromTree)(snapshot, this.storage);
953
+ this.baseSnapshotBlobs = await (0, containerStorageAdapter_1.getBlobContentsFromTree)(snapshot, this.storageAdapter);
925
954
  }
926
955
  }
927
956
  const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
@@ -957,7 +986,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
957
986
  for (const message of pendingLocalState.savedOps) {
958
987
  this.processRemoteMessage(message);
959
988
  // allow runtime to apply stashed ops at this op's sequence number
960
- await this.context.notifyOpReplay(message);
989
+ await ((_c = (_b = this.runtime).notifyOpReplay) === null || _c === void 0 ? void 0 : _c.call(_b, message));
961
990
  }
962
991
  pendingLocalState.savedOps = [];
963
992
  // now set clientId to stashed clientId so live ops are correctly processed as local
@@ -1196,7 +1225,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1196
1225
  });
1197
1226
  deltaManager.on("disconnect", (reason, error) => {
1198
1227
  var _a;
1199
- (_a = this.collabWindowTracker) === null || _a === void 0 ? void 0 : _a.stopSequenceNumberUpdate();
1228
+ (_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyDisconnect();
1200
1229
  if (!this.closed) {
1201
1230
  this.connectionStateHandler.receivedDisconnectEvent(reason, error);
1202
1231
  }
@@ -1253,7 +1282,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1253
1282
  else if (value === connectionState_1.ConnectionState.CatchingUp) {
1254
1283
  // This info is of most interesting while Catching Up.
1255
1284
  checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
1256
- if (this.deltaManager.hasCheckpointSequenceNumber) {
1285
+ // Need to check that we have already loaded and fetched the snapshot.
1286
+ if (this.deltaManager.hasCheckpointSequenceNumber &&
1287
+ this._lifecycleState === "loaded") {
1257
1288
  opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
1258
1289
  }
1259
1290
  }
@@ -1340,7 +1371,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1340
1371
  return -1;
1341
1372
  }
1342
1373
  this.messageCountAfterDisconnection += 1;
1343
- (_a = this.collabWindowTracker) === null || _a === void 0 ? void 0 : _a.stopSequenceNumberUpdate();
1374
+ (_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyMessageSent();
1344
1375
  return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
1345
1376
  }
1346
1377
  processRemoteMessage(message) {
@@ -1348,24 +1379,51 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1348
1379
  this.savedOps.push(message);
1349
1380
  }
1350
1381
  const local = this.clientId === message.clientId;
1382
+ // Check and report if we're getting messages from a clientId that we previously
1383
+ // flagged should have left, or from a client that's not in the quorum but should be
1384
+ if (message.clientId != null) {
1385
+ const client = this.protocolHandler.quorum.getMember(message.clientId);
1386
+ if (client === undefined && message.type !== protocol_definitions_1.MessageType.ClientJoin) {
1387
+ // pre-0.58 error message: messageClientIdMissingFromQuorum
1388
+ throw new Error("Remote message's clientId is missing from the quorum");
1389
+ }
1390
+ // Here checking canBeCoalescedByService is used as an approximation of "is benign to process despite being unexpected".
1391
+ // It's still not good to see these messages from unexpected clientIds, but since they don't harm the integrity of the
1392
+ // document we don't need to blow up aggressively.
1393
+ if (this.clientsWhoShouldHaveLeft.has(message.clientId) &&
1394
+ !(0, driver_utils_1.canBeCoalescedByService)(message)) {
1395
+ // pre-0.58 error message: messageClientIdShouldHaveLeft
1396
+ throw new Error("Remote message's clientId already should have left");
1397
+ }
1398
+ }
1351
1399
  // Allow the protocol handler to process the message
1352
1400
  const result = this.protocolHandler.processMessage(message, local);
1353
1401
  // Forward messages to the loaded runtime for processing
1354
- this.context.process(message, local);
1402
+ this.runtime.process(message, local);
1355
1403
  // Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
1356
1404
  if (this.activeConnection()) {
1357
- if (this.collabWindowTracker === undefined) {
1405
+ if (this.noopHeuristic === undefined) {
1406
+ const serviceConfiguration = this.deltaManager.serviceConfiguration;
1358
1407
  // Note that config from first connection will be used for this container's lifetime.
1359
1408
  // That means that if relay service changes settings, such changes will impact only newly booted
1360
1409
  // clients.
1361
1410
  // All existing will continue to use settings they got earlier.
1362
- (0, common_utils_1.assert)(this.serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
1363
- this.collabWindowTracker = new collabWindowTracker_1.CollabWindowTracker((type) => {
1364
- (0, common_utils_1.assert)(this.activeConnection(), 0x241 /* "disconnect should result in stopSequenceNumberUpdate() call" */);
1365
- this.submitMessage(type);
1366
- }, this.serviceConfiguration.noopTimeFrequency, this.serviceConfiguration.noopCountFrequency);
1411
+ (0, common_utils_1.assert)(serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
1412
+ this.noopHeuristic = new noopHeuristic_1.NoopHeuristic(serviceConfiguration.noopTimeFrequency, serviceConfiguration.noopCountFrequency);
1413
+ this.noopHeuristic.on("wantsNoop", () => {
1414
+ // On disconnect we notify the heuristic which should prevent it from wanting a noop.
1415
+ // Hitting this assert would imply we lost activeConnection between notifying the heuristic of a processed message and
1416
+ // running the microtask that the heuristic queued in response.
1417
+ (0, common_utils_1.assert)(this.activeConnection(), 0x241 /* "Trying to send noop without active connection" */);
1418
+ this.submitMessage(protocol_definitions_1.MessageType.NoOp);
1419
+ });
1420
+ }
1421
+ this.noopHeuristic.notifyMessageProcessed(message);
1422
+ // The contract with the protocolHandler is that returning "immediateNoOp" is equivalent to "please immediately accept the proposal I just processed".
1423
+ if (result.immediateNoOp === true) {
1424
+ // ADO:1385: Remove cast and use MessageType once definition changes propagate
1425
+ this.submitMessage(driver_utils_1.MessageType2.Accept);
1367
1426
  }
1368
- this.collabWindowTracker.scheduleSequenceNumberUpdate(message, result.immediateNoOp === true);
1369
1427
  }
1370
1428
  this.emit("op", message);
1371
1429
  }
@@ -1374,12 +1432,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1374
1432
  }
1375
1433
  processSignal(message) {
1376
1434
  // No clientId indicates a system signal message.
1377
- if (message.clientId === null) {
1435
+ if ((0, protocol_1.protocolHandlerShouldProcessSignal)(message)) {
1378
1436
  this.protocolHandler.processSignal(message);
1379
1437
  }
1380
1438
  else {
1381
1439
  const local = this.clientId === message.clientId;
1382
- this.context.processSignal(message, local);
1440
+ this.runtime.processSignal(message, local);
1383
1441
  }
1384
1442
  }
1385
1443
  /**
@@ -1412,21 +1470,37 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1412
1470
  await this.instantiateContext(existing, codeDetails, snapshot);
1413
1471
  }
1414
1472
  async instantiateContext(existing, codeDetails, snapshot, pendingLocalState) {
1415
- var _a;
1416
- (0, common_utils_1.assert)(((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing context not disposed" */);
1473
+ var _a, _b;
1474
+ (0, common_utils_1.assert)(((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing runtime not disposed" */);
1417
1475
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
1418
1476
  // are set. Global requests will still go directly to the loader
1419
1477
  const maybeLoader = this.scope;
1420
1478
  const loader = new loader_1.RelativeLoader(this, maybeLoader.ILoader);
1421
- 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);
1422
- this.emit("contextChanged", codeDetails);
1423
- }
1424
- updateDirtyContainerState(dirty) {
1425
- if (this._dirtyContainer === dirty) {
1426
- return;
1479
+ const loadCodeResult = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "CodeLoad" }, async () => this.codeLoader.load(codeDetails));
1480
+ this._loadedModule = {
1481
+ module: loadCodeResult.module,
1482
+ // An older interface ICodeLoader could return an IFluidModule which didn't have details.
1483
+ // If we're using one of those older ICodeLoaders, then we fix up the module with the specified details here.
1484
+ // TODO: Determine if this is still a realistic scenario or if this fixup could be removed.
1485
+ details: (_b = loadCodeResult.details) !== null && _b !== void 0 ? _b : codeDetails,
1486
+ };
1487
+ const fluidExport = this._loadedModule.module.fluidExport;
1488
+ const runtimeFactory = fluidExport === null || fluidExport === void 0 ? void 0 : fluidExport.IRuntimeFactory;
1489
+ if (runtimeFactory === undefined) {
1490
+ throw new Error(packageNotFactoryError);
1427
1491
  }
1428
- this._dirtyContainer = dirty;
1429
- this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
1492
+ const getSpecifiedCodeDetails = () => {
1493
+ var _a;
1494
+ return ((_a = this.protocolHandler.quorum.get("code")) !== null && _a !== void 0 ? _a : this.protocolHandler.quorum.get("code2"));
1495
+ };
1496
+ const context = new containerContext_1.ContainerContext(this.options, this.scope, snapshot, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, 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), this.updateDirtyContainerState, this.getAbsoluteUrl, () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; }, () => this.clientId, () => this._deltaManager.serviceConfiguration, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState);
1497
+ this._lifecycleEvents.once("disposed", () => {
1498
+ context.dispose();
1499
+ });
1500
+ this._runtime = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
1501
+ this._lifecycleEvents.emit("runtimeInstantiated");
1502
+ this._loadedCodeDetails = codeDetails;
1503
+ this.emit("contextChanged", codeDetails);
1430
1504
  }
1431
1505
  /**
1432
1506
  * Set the connected state of the ContainerContext
@@ -1436,17 +1510,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1436
1510
  */
1437
1511
  setContextConnectedState(state, readonly) {
1438
1512
  var _a;
1439
- if (((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
1513
+ if (((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
1440
1514
  /**
1441
1515
  * We want to lie to the ContainerRuntime when we are in readonly mode to prevent issues with pending
1442
1516
  * ops getting through to the DeltaManager.
1443
1517
  * The ContainerRuntime's "connected" state simply means it is ok to send ops
1444
1518
  * See https://dev.azure.com/fluidframework/internal/_workitems/edit/1246
1445
1519
  */
1446
- this.context.setConnectionState(state && !readonly, this.clientId);
1520
+ this.runtime.setConnectionState(state && !readonly, this.clientId);
1447
1521
  }
1448
1522
  }
1449
1523
  }
1450
1524
  exports.Container = Container;
1451
- Container.version = "^0.1.0";
1452
1525
  //# sourceMappingURL=container.js.map