@fluidframework/container-loader 2.0.0-internal.6.1.0 → 2.0.0-internal.6.2.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 (94) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +4 -3
  3. package/dist/connectionManager.d.ts +1 -1
  4. package/dist/connectionManager.d.ts.map +1 -1
  5. package/dist/connectionManager.js +2 -3
  6. package/dist/connectionManager.js.map +1 -1
  7. package/dist/container.d.ts +8 -1
  8. package/dist/container.d.ts.map +1 -1
  9. package/dist/container.js +57 -46
  10. package/dist/container.js.map +1 -1
  11. package/dist/containerContext.d.ts +6 -1
  12. package/dist/containerContext.d.ts.map +1 -1
  13. package/dist/containerContext.js +8 -1
  14. package/dist/containerContext.js.map +1 -1
  15. package/dist/contracts.d.ts +2 -2
  16. package/dist/contracts.d.ts.map +1 -1
  17. package/dist/contracts.js.map +1 -1
  18. package/dist/deltaManager.d.ts +2 -3
  19. package/dist/deltaManager.d.ts.map +1 -1
  20. package/dist/deltaManager.js +11 -11
  21. package/dist/deltaManager.js.map +1 -1
  22. package/dist/disposal.d.ts +2 -2
  23. package/dist/disposal.d.ts.map +1 -1
  24. package/dist/disposal.js +1 -1
  25. package/dist/disposal.js.map +1 -1
  26. package/dist/error.d.ts +23 -0
  27. package/dist/error.d.ts.map +1 -0
  28. package/dist/error.js +32 -0
  29. package/dist/error.js.map +1 -0
  30. package/dist/loader.d.ts +9 -2
  31. package/dist/loader.d.ts.map +1 -1
  32. package/dist/loader.js +12 -7
  33. package/dist/loader.js.map +1 -1
  34. package/dist/noopHeuristic.d.ts +1 -1
  35. package/dist/noopHeuristic.d.ts.map +1 -1
  36. package/dist/noopHeuristic.js.map +1 -1
  37. package/dist/packageVersion.d.ts +1 -1
  38. package/dist/packageVersion.js +1 -1
  39. package/dist/packageVersion.js.map +1 -1
  40. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  41. package/dist/retriableDocumentStorageService.js +2 -2
  42. package/dist/retriableDocumentStorageService.js.map +1 -1
  43. package/lib/connectionManager.d.ts +1 -1
  44. package/lib/connectionManager.d.ts.map +1 -1
  45. package/lib/connectionManager.js +1 -2
  46. package/lib/connectionManager.js.map +1 -1
  47. package/lib/container.d.ts +8 -1
  48. package/lib/container.d.ts.map +1 -1
  49. package/lib/container.js +45 -34
  50. package/lib/container.js.map +1 -1
  51. package/lib/containerContext.d.ts +6 -1
  52. package/lib/containerContext.d.ts.map +1 -1
  53. package/lib/containerContext.js +8 -1
  54. package/lib/containerContext.js.map +1 -1
  55. package/lib/contracts.d.ts +2 -2
  56. package/lib/contracts.d.ts.map +1 -1
  57. package/lib/contracts.js.map +1 -1
  58. package/lib/deltaManager.d.ts +2 -3
  59. package/lib/deltaManager.d.ts.map +1 -1
  60. package/lib/deltaManager.js +2 -2
  61. package/lib/deltaManager.js.map +1 -1
  62. package/lib/disposal.d.ts +2 -2
  63. package/lib/disposal.d.ts.map +1 -1
  64. package/lib/disposal.js +1 -1
  65. package/lib/disposal.js.map +1 -1
  66. package/lib/error.d.ts +23 -0
  67. package/lib/error.d.ts.map +1 -0
  68. package/lib/error.js +28 -0
  69. package/lib/error.js.map +1 -0
  70. package/lib/loader.d.ts +9 -2
  71. package/lib/loader.d.ts.map +1 -1
  72. package/lib/loader.js +11 -6
  73. package/lib/loader.js.map +1 -1
  74. package/lib/noopHeuristic.d.ts +1 -1
  75. package/lib/noopHeuristic.d.ts.map +1 -1
  76. package/lib/noopHeuristic.js.map +1 -1
  77. package/lib/packageVersion.d.ts +1 -1
  78. package/lib/packageVersion.js +1 -1
  79. package/lib/packageVersion.js.map +1 -1
  80. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  81. package/lib/retriableDocumentStorageService.js +1 -1
  82. package/lib/retriableDocumentStorageService.js.map +1 -1
  83. package/package.json +14 -16
  84. package/src/connectionManager.ts +8 -3
  85. package/src/container.ts +78 -43
  86. package/src/containerContext.ts +8 -0
  87. package/src/contracts.ts +1 -2
  88. package/src/deltaManager.ts +12 -10
  89. package/src/disposal.ts +2 -2
  90. package/src/error.ts +44 -0
  91. package/src/loader.ts +30 -5
  92. package/src/noopHeuristic.ts +1 -1
  93. package/src/packageVersion.ts +1 -1
  94. package/src/retriableDocumentStorageService.ts +1 -3
package/src/container.ts CHANGED
@@ -7,7 +7,6 @@
7
7
  import merge from "lodash/merge";
8
8
 
9
9
  import { v4 as uuid } from "uuid";
10
- import { IEvent } from "@fluidframework/common-definitions";
11
10
  import {
12
11
  TypedEventEmitter,
13
12
  assert,
@@ -15,12 +14,14 @@ import {
15
14
  unreachableCase,
16
15
  } from "@fluidframework/common-utils";
17
16
  import {
17
+ IEvent,
18
18
  ITelemetryProperties,
19
19
  TelemetryEventCategory,
20
20
  IRequest,
21
21
  IResponse,
22
22
  IFluidRouter,
23
23
  FluidObject,
24
+ LogLevel,
24
25
  } from "@fluidframework/core-interfaces";
25
26
  import {
26
27
  AttachState,
@@ -43,7 +44,6 @@ import {
43
44
  ReadOnlyInfo,
44
45
  isFluidCodeDetails,
45
46
  } from "@fluidframework/container-definitions";
46
- import { GenericError, UsageError } from "@fluidframework/container-utils";
47
47
  import {
48
48
  IDocumentService,
49
49
  IDocumentServiceFactory,
@@ -92,6 +92,8 @@ import {
92
92
  wrapError,
93
93
  ITelemetryLoggerExt,
94
94
  formatTick,
95
+ GenericError,
96
+ UsageError,
95
97
  } from "@fluidframework/telemetry-utils";
96
98
  import { Audience } from "./audience";
97
99
  import { ContainerContext } from "./containerContext";
@@ -217,6 +219,10 @@ export interface IContainerCreateProps {
217
219
  */
218
220
  readonly detachedBlobStorage?: IDetachedBlobStorage;
219
221
 
222
+ /**
223
+ * Optional property for allowing the container to use a custom
224
+ * protocol implementation for handling the quorum and/or the audience.
225
+ */
220
226
  readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
221
227
  }
222
228
 
@@ -424,7 +430,11 @@ export class Container
424
430
  // Depending where error happens, we can be attempting to connect to web socket
425
431
  // and continuously retrying (consider offline mode)
426
432
  // Host has no container to close, so it's prudent to do it here
433
+ // Note: We could only dispose the container instead of just close but that would
434
+ // the telemetry where users sometimes search for ContainerClose event to look
435
+ // for load failures. So not removing this at this time.
427
436
  container.close(err);
437
+ container.dispose(err);
428
438
  onClosed(err);
429
439
  },
430
440
  );
@@ -747,6 +757,7 @@ export class Container
747
757
 
748
758
  this.connectionTransitionTimes[ConnectionState.Disconnected] = performance.now();
749
759
  const pendingLocalState = loadProps?.pendingLocalState;
760
+ this._clientId = pendingLocalState?.clientId;
750
761
 
751
762
  this._canReconnect = canReconnect ?? true;
752
763
  this.clientDetailsOverride = clientDetailsOverride;
@@ -1120,7 +1131,8 @@ export class Container
1120
1131
  savedOps: this.savedOps,
1121
1132
  url: this.resolvedUrl.url,
1122
1133
  term: OnlyValidTermValue,
1123
- clientId: this.clientId,
1134
+ // no need to save this if there is no pending runtime state
1135
+ clientId: pendingRuntimeState !== undefined ? this.clientId : undefined,
1124
1136
  };
1125
1137
 
1126
1138
  this.mc.logger.sendTelemetryEvent({ eventName: "GetPendingLocalState" });
@@ -1151,7 +1163,10 @@ export class Container
1151
1163
  return JSON.stringify(combinedSummary);
1152
1164
  }
1153
1165
 
1154
- public async attach(request: IRequest): Promise<void> {
1166
+ public async attach(
1167
+ request: IRequest,
1168
+ attachProps?: { deltaConnection?: "none" | "delayed" },
1169
+ ): Promise<void> {
1155
1170
  await PerformanceEvent.timedExecAsync(
1156
1171
  this.mc.logger,
1157
1172
  { eventName: "Attach" },
@@ -1277,10 +1292,13 @@ export class Container
1277
1292
  this.emit("attached");
1278
1293
 
1279
1294
  if (!this.closed) {
1280
- this.resumeInternal({
1281
- fetchOpsFromStorage: false,
1282
- reason: { text: "createDetached" },
1283
- });
1295
+ this.handleDeltaConnectionArg(
1296
+ {
1297
+ fetchOpsFromStorage: false,
1298
+ reason: { text: "createDetached" },
1299
+ },
1300
+ attachProps?.deltaConnection,
1301
+ );
1284
1302
  }
1285
1303
  } catch (error) {
1286
1304
  // add resolved URL on error object so that host has the ability to find this document and delete it
@@ -1505,6 +1523,7 @@ export class Container
1505
1523
  pendingLocalState: IPendingContainerState | undefined,
1506
1524
  loadToSequenceNumber: number | undefined,
1507
1525
  ) {
1526
+ const timings: Record<string, number> = { phase1: performance.now() };
1508
1527
  this.service = await this.serviceFactory.createDocumentService(
1509
1528
  resolvedUrl,
1510
1529
  this.subLogger,
@@ -1543,6 +1562,7 @@ export class Container
1543
1562
 
1544
1563
  this._attachState = AttachState.Attached;
1545
1564
 
1565
+ timings.phase2 = performance.now();
1546
1566
  // Fetch specified snapshot.
1547
1567
  const { snapshot, versionId } =
1548
1568
  pendingLocalState === undefined
@@ -1640,13 +1660,12 @@ export class Container
1640
1660
  );
1641
1661
  break;
1642
1662
  case "sequenceNumber":
1643
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "sequenceNumber");
1644
- break;
1645
1663
  case "cached":
1646
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "cached");
1647
- break;
1648
1664
  case "all":
1649
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "all");
1665
+ opsBeforeReturnP = this.attachDeltaManagerOpHandler(
1666
+ dmAttributes,
1667
+ loadMode.opsBeforeReturn,
1668
+ );
1650
1669
  break;
1651
1670
  default:
1652
1671
  unreachableCase(loadMode.opsBeforeReturn);
@@ -1656,11 +1675,13 @@ export class Container
1656
1675
  // Initialize the protocol handler
1657
1676
  await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
1658
1677
 
1678
+ timings.phase3 = performance.now();
1659
1679
  const codeDetails = this.getCodeDetailsFromQuorum();
1660
1680
  await this.instantiateRuntime(
1661
1681
  codeDetails,
1662
1682
  snapshot,
1663
- pendingLocalState?.pendingRuntimeState,
1683
+ // give runtime a dummy value so it knows we're loading from a stash blob
1684
+ pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined,
1664
1685
  );
1665
1686
 
1666
1687
  // replay saved ops
@@ -1672,13 +1693,6 @@ export class Container
1672
1693
  await this.runtime.notifyOpReplay?.(message);
1673
1694
  }
1674
1695
  pendingLocalState.savedOps = [];
1675
-
1676
- // now set clientId to stashed clientId so live ops are correctly processed as local
1677
- assert(
1678
- this.clientId === undefined,
1679
- 0x5d6 /* Unexpected clientId when setting stashed clientId */,
1680
- );
1681
- this._clientId = pendingLocalState?.clientId;
1682
1696
  }
1683
1697
 
1684
1698
  // We might have hit some failure that did not manifest itself in exception in this flow,
@@ -1702,27 +1716,11 @@ export class Container
1702
1716
  this._deltaManager.inbound.pause();
1703
1717
  }
1704
1718
 
1705
- switch (loadMode.deltaConnection) {
1706
- case undefined:
1707
- if (pendingLocalState) {
1708
- // connect to delta stream now since we did not before
1709
- this.connectToDeltaStream(connectionArgs);
1710
- }
1711
- // intentional fallthrough
1712
- case "delayed":
1713
- assert(
1714
- this.inboundQueuePausedFromInit,
1715
- 0x346 /* inboundQueuePausedFromInit should be true */,
1716
- );
1717
- this.inboundQueuePausedFromInit = false;
1718
- this._deltaManager.inbound.resume();
1719
- this._deltaManager.inboundSignal.resume();
1720
- break;
1721
- case "none":
1722
- break;
1723
- default:
1724
- unreachableCase(loadMode.deltaConnection);
1725
- }
1719
+ this.handleDeltaConnectionArg(
1720
+ connectionArgs,
1721
+ loadMode.deltaConnection,
1722
+ pendingLocalState !== undefined,
1723
+ );
1726
1724
  }
1727
1725
 
1728
1726
  // If we have not yet reached `loadToSequenceNumber`, we will wait for ops to arrive until we reach it
@@ -1752,7 +1750,15 @@ export class Container
1752
1750
 
1753
1751
  // Internal context is fully loaded at this point
1754
1752
  this.setLoaded();
1755
-
1753
+ timings.end = performance.now();
1754
+ this.subLogger.sendTelemetryEvent(
1755
+ {
1756
+ eventName: "LoadStagesTimings",
1757
+ details: JSON.stringify(timings),
1758
+ },
1759
+ undefined,
1760
+ LogLevel.verbose,
1761
+ );
1756
1762
  return {
1757
1763
  sequenceNumber: attributes.sequenceNumber,
1758
1764
  version: versionId,
@@ -2408,6 +2414,7 @@ export class Container
2408
2414
  (error?: ICriticalContainerError) => this.close(error),
2409
2415
  this.updateDirtyContainerState,
2410
2416
  this.getAbsoluteUrl,
2417
+ () => this.resolvedUrl?.id,
2411
2418
  () => this.clientId,
2412
2419
  () => this.attachState,
2413
2420
  () => this.connected,
@@ -2453,6 +2460,34 @@ export class Container
2453
2460
  this.runtime.setConnectionState(state && !readonly, this.clientId);
2454
2461
  }
2455
2462
  }
2463
+
2464
+ private handleDeltaConnectionArg(
2465
+ connectionArgs: IConnectionArgs,
2466
+ deltaConnectionArg?: "none" | "delayed",
2467
+ canConnect: boolean = true,
2468
+ ) {
2469
+ switch (deltaConnectionArg) {
2470
+ case undefined:
2471
+ if (canConnect) {
2472
+ // connect to delta stream now since we did not before
2473
+ this.connectToDeltaStream(connectionArgs);
2474
+ }
2475
+ // intentional fallthrough
2476
+ case "delayed":
2477
+ assert(
2478
+ this.inboundQueuePausedFromInit,
2479
+ 0x346 /* inboundQueuePausedFromInit should be true */,
2480
+ );
2481
+ this.inboundQueuePausedFromInit = false;
2482
+ this._deltaManager.inbound.resume();
2483
+ this._deltaManager.inboundSignal.resume();
2484
+ break;
2485
+ case "none":
2486
+ break;
2487
+ default:
2488
+ unreachableCase(deltaConnectionArg);
2489
+ }
2490
+ }
2456
2491
  }
2457
2492
 
2458
2493
  /**
@@ -45,6 +45,13 @@ export class ContainerContext implements IContainerContext {
45
45
  return this._getClientId();
46
46
  }
47
47
 
48
+ /**
49
+ * DISCLAIMER: this id is only for telemetry purposes. Not suitable for any other usages.
50
+ */
51
+ public get id(): string {
52
+ return this._getContainerDiagnosticId() ?? "";
53
+ }
54
+
48
55
  /**
49
56
  * When true, ops are free to flow
50
57
  * When false, ops should be kept as pending or rejected
@@ -83,6 +90,7 @@ export class ContainerContext implements IContainerContext {
83
90
  public readonly closeFn: (error?: ICriticalContainerError) => void,
84
91
  public readonly updateDirtyContainerState: (dirty: boolean) => void,
85
92
  public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>,
93
+ private readonly _getContainerDiagnosticId: () => string | undefined,
86
94
  private readonly _getClientId: () => string | undefined,
87
95
  private readonly _getAttachState: () => AttachState,
88
96
  private readonly _getConnected: () => boolean,
package/src/contracts.ts CHANGED
@@ -3,12 +3,11 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryProperties } from "@fluidframework/core-interfaces";
6
+ import { IErrorBase, ITelemetryProperties } from "@fluidframework/core-interfaces";
7
7
  import {
8
8
  IConnectionDetails,
9
9
  ICriticalContainerError,
10
10
  IDeltaQueue,
11
- IErrorBase,
12
11
  IFluidCodeDetails,
13
12
  isFluidPackage,
14
13
  ReadOnlyInfo,
@@ -4,22 +4,29 @@
4
4
  */
5
5
 
6
6
  import { v4 as uuid } from "uuid";
7
- import { IEventProvider } from "@fluidframework/common-definitions";
8
- import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
7
+ import {
8
+ IThrottlingWarning,
9
+ IEventProvider,
10
+ ITelemetryProperties,
11
+ ITelemetryErrorEvent,
12
+ } from "@fluidframework/core-interfaces";
9
13
  import {
10
14
  ICriticalContainerError,
11
15
  IDeltaManager,
12
16
  IDeltaManagerEvents,
13
17
  IDeltaQueue,
14
- IThrottlingWarning,
15
18
  } from "@fluidframework/container-definitions";
16
19
  import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
17
20
  import {
21
+ DataProcessingError,
22
+ extractSafePropertiesFromMessage,
18
23
  normalizeError,
19
24
  logIfFalse,
20
25
  safeRaiseEvent,
21
26
  isFluidError,
22
27
  ITelemetryLoggerExt,
28
+ DataCorruptionError,
29
+ UsageError,
23
30
  } from "@fluidframework/telemetry-utils";
24
31
  import {
25
32
  IDocumentDeltaStorageService,
@@ -34,13 +41,7 @@ import {
34
41
  ConnectionMode,
35
42
  } from "@fluidframework/protocol-definitions";
36
43
  import { NonRetryableError, isRuntimeMessage, MessageType2 } from "@fluidframework/driver-utils";
37
- import {
38
- ThrottlingWarning,
39
- DataCorruptionError,
40
- extractSafePropertiesFromMessage,
41
- DataProcessingError,
42
- UsageError,
43
- } from "@fluidframework/container-utils";
44
+
44
45
  import {
45
46
  IConnectionDetailsInternal,
46
47
  IConnectionManager,
@@ -49,6 +50,7 @@ import {
49
50
  } from "./contracts";
50
51
  import { DeltaQueue } from "./deltaQueue";
51
52
  import { OnlyValidTermValue } from "./protocol";
53
+ import { ThrottlingWarning } from "./error";
52
54
 
53
55
  export interface IConnectionArgs {
54
56
  mode?: ConnectionMode;
package/src/disposal.ts CHANGED
@@ -3,11 +3,11 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IDisposable } from "@fluidframework/common-definitions";
6
+ import { IDisposable } from "@fluidframework/core-interfaces";
7
7
 
8
8
  /**
9
9
  * Returns a wrapper around the provided function, which will only invoke the inner function if the provided
10
- * {@link @fluidframework/common-definitions#IDisposable | disposable} object has not yet been disposed.
10
+ * {@link @fluidframework/core-interfaces#IDisposable | disposable} object has not yet been disposed.
11
11
  *
12
12
  * @throws Will throw an error if the item has already been disposed.
13
13
  */
package/src/error.ts ADDED
@@ -0,0 +1,44 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { ITelemetryProperties, IThrottlingWarning } from "@fluidframework/core-interfaces";
7
+ import { ContainerErrorTypes } from "@fluidframework/container-definitions";
8
+ import {
9
+ IFluidErrorBase,
10
+ ITelemetryLoggerExt,
11
+ LoggingError,
12
+ wrapErrorAndLog,
13
+ } from "@fluidframework/telemetry-utils";
14
+
15
+ /**
16
+ * Warning emitted when requests to storage are being throttled.
17
+ */
18
+ export class ThrottlingWarning extends LoggingError implements IThrottlingWarning, IFluidErrorBase {
19
+ /**
20
+ * {@inheritDoc @fluidframework/telemetry-utils#IFluidErrorBase.errorType}
21
+ */
22
+ public readonly errorType = ContainerErrorTypes.throttlingError;
23
+
24
+ private constructor(
25
+ message: string,
26
+ readonly retryAfterSeconds: number,
27
+ props?: ITelemetryProperties,
28
+ ) {
29
+ super(message, props);
30
+ }
31
+
32
+ /**
33
+ * Wrap the given error as a ThrottlingWarning
34
+ * Only preserves the error message, and applies the given retry after to the new warning object
35
+ */
36
+ public static wrap(
37
+ error: unknown,
38
+ retryAfterSeconds: number,
39
+ logger: ITelemetryLoggerExt,
40
+ ): IThrottlingWarning {
41
+ const newErrorFn = (errMsg: string) => new ThrottlingWarning(errMsg, retryAfterSeconds);
42
+ return wrapErrorAndLog(error, newErrorFn, logger);
43
+ }
44
+ }
package/src/loader.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  PerformanceEvent,
13
13
  sessionStorageConfigProvider,
14
14
  createChildMonitoringContext,
15
+ UsageError,
15
16
  } from "@fluidframework/telemetry-utils";
16
17
  import {
17
18
  ITelemetryBaseLogger,
@@ -37,7 +38,7 @@ import {
37
38
  IResolvedUrl,
38
39
  IUrlResolver,
39
40
  } from "@fluidframework/driver-definitions";
40
- import { UsageError } from "@fluidframework/container-utils";
41
+ import { IClientDetails } from "@fluidframework/protocol-definitions";
41
42
  import { Container, IPendingContainerState } from "./container";
42
43
  import { IParsedUrl, parseUrl } from "./utils";
43
44
  import { pkgVersion } from "./packageVersion";
@@ -357,8 +358,20 @@ export class Loader implements IHostLoader {
357
358
  return this;
358
359
  }
359
360
 
360
- public async createDetachedContainer(codeDetails: IFluidCodeDetails): Promise<IContainer> {
361
- const container = await Container.createDetached(this.services, codeDetails);
361
+ public async createDetachedContainer(
362
+ codeDetails: IFluidCodeDetails,
363
+ createDetachedProps?: {
364
+ canReconnect?: boolean;
365
+ clientDetailsOverride?: IClientDetails;
366
+ },
367
+ ): Promise<IContainer> {
368
+ const container = await Container.createDetached(
369
+ {
370
+ ...createDetachedProps,
371
+ ...this.services,
372
+ },
373
+ codeDetails,
374
+ );
362
375
 
363
376
  if (this.cachingEnabled) {
364
377
  container.once("attached", () => {
@@ -373,8 +386,20 @@ export class Loader implements IHostLoader {
373
386
  return container;
374
387
  }
375
388
 
376
- public async rehydrateDetachedContainerFromSnapshot(snapshot: string): Promise<IContainer> {
377
- return Container.rehydrateDetachedFromSnapshot(this.services, snapshot);
389
+ public async rehydrateDetachedContainerFromSnapshot(
390
+ snapshot: string,
391
+ createDetachedProps?: {
392
+ canReconnect?: boolean;
393
+ clientDetailsOverride?: IClientDetails;
394
+ },
395
+ ): Promise<IContainer> {
396
+ return Container.rehydrateDetachedFromSnapshot(
397
+ {
398
+ ...createDetachedProps,
399
+ ...this.services,
400
+ },
401
+ snapshot,
402
+ );
378
403
  }
379
404
 
380
405
  public async resolve(request: IRequest, pendingLocalState?: string): Promise<IContainer> {
@@ -6,7 +6,7 @@
6
6
  import { assert, Timer, TypedEventEmitter } from "@fluidframework/common-utils";
7
7
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
8
8
  import { isRuntimeMessage } from "@fluidframework/driver-utils";
9
- import { IEvent } from "@fluidframework/common-definitions";
9
+ import { IEvent } from "@fluidframework/core-interfaces";
10
10
 
11
11
  const defaultNoopTimeFrequency = 2000;
12
12
  const defaultNoopCountFrequency = 50;
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-internal.6.1.0";
9
+ export const pkgVersion = "2.0.0-internal.6.2.0";
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { assert } from "@fluidframework/common-utils";
7
- import { GenericError } from "@fluidframework/container-utils";
8
7
  import {
9
8
  FetchSource,
10
9
  IDocumentStorageService,
@@ -19,8 +18,7 @@ import {
19
18
  IVersion,
20
19
  } from "@fluidframework/protocol-definitions";
21
20
  import { IDisposable } from "@fluidframework/core-interfaces";
22
-
23
- import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
21
+ import { GenericError, ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
24
22
  import { runWithRetry } from "@fluidframework/driver-utils";
25
23
 
26
24
  export class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {