@fluidframework/container-runtime 0.52.0 → 0.54.0-47413

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 (132) hide show
  1. package/dist/containerHandleContext.d.ts +0 -1
  2. package/dist/containerHandleContext.d.ts.map +1 -1
  3. package/dist/containerHandleContext.js +0 -1
  4. package/dist/containerHandleContext.js.map +1 -1
  5. package/dist/containerRuntime.d.ts +43 -19
  6. package/dist/containerRuntime.d.ts.map +1 -1
  7. package/dist/containerRuntime.js +201 -111
  8. package/dist/containerRuntime.js.map +1 -1
  9. package/dist/dataStoreContext.d.ts +33 -4
  10. package/dist/dataStoreContext.d.ts.map +1 -1
  11. package/dist/dataStoreContext.js +45 -17
  12. package/dist/dataStoreContext.js.map +1 -1
  13. package/dist/dataStores.d.ts +14 -10
  14. package/dist/dataStores.d.ts.map +1 -1
  15. package/dist/dataStores.js +73 -41
  16. package/dist/dataStores.js.map +1 -1
  17. package/dist/garbageCollection.d.ts +82 -15
  18. package/dist/garbageCollection.d.ts.map +1 -1
  19. package/dist/garbageCollection.js +359 -26
  20. package/dist/garbageCollection.js.map +1 -1
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +11 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/packageVersion.d.ts +1 -1
  26. package/dist/packageVersion.d.ts.map +1 -1
  27. package/dist/packageVersion.js +1 -1
  28. package/dist/packageVersion.js.map +1 -1
  29. package/dist/pendingStateManager.d.ts +0 -1
  30. package/dist/pendingStateManager.d.ts.map +1 -1
  31. package/dist/pendingStateManager.js +0 -36
  32. package/dist/pendingStateManager.js.map +1 -1
  33. package/dist/runningSummarizer.d.ts +3 -2
  34. package/dist/runningSummarizer.d.ts.map +1 -1
  35. package/dist/runningSummarizer.js +6 -6
  36. package/dist/runningSummarizer.js.map +1 -1
  37. package/dist/summarizer.d.ts +23 -3
  38. package/dist/summarizer.d.ts.map +1 -1
  39. package/dist/summarizer.js +135 -45
  40. package/dist/summarizer.js.map +1 -1
  41. package/dist/summarizerTypes.d.ts +3 -10
  42. package/dist/summarizerTypes.d.ts.map +1 -1
  43. package/dist/summarizerTypes.js.map +1 -1
  44. package/dist/summaryFormat.d.ts +10 -1
  45. package/dist/summaryFormat.d.ts.map +1 -1
  46. package/dist/summaryFormat.js +2 -1
  47. package/dist/summaryFormat.js.map +1 -1
  48. package/dist/summaryGenerator.d.ts.map +1 -1
  49. package/dist/summaryGenerator.js +1 -3
  50. package/dist/summaryGenerator.js.map +1 -1
  51. package/dist/summaryManager.d.ts +0 -15
  52. package/dist/summaryManager.d.ts.map +1 -1
  53. package/dist/summaryManager.js +1 -35
  54. package/dist/summaryManager.js.map +1 -1
  55. package/lib/containerHandleContext.d.ts +0 -1
  56. package/lib/containerHandleContext.d.ts.map +1 -1
  57. package/lib/containerHandleContext.js +0 -1
  58. package/lib/containerHandleContext.js.map +1 -1
  59. package/lib/containerRuntime.d.ts +43 -19
  60. package/lib/containerRuntime.d.ts.map +1 -1
  61. package/lib/containerRuntime.js +206 -117
  62. package/lib/containerRuntime.js.map +1 -1
  63. package/lib/dataStoreContext.d.ts +33 -4
  64. package/lib/dataStoreContext.d.ts.map +1 -1
  65. package/lib/dataStoreContext.js +45 -17
  66. package/lib/dataStoreContext.js.map +1 -1
  67. package/lib/dataStores.d.ts +14 -10
  68. package/lib/dataStores.d.ts.map +1 -1
  69. package/lib/dataStores.js +76 -44
  70. package/lib/dataStores.js.map +1 -1
  71. package/lib/garbageCollection.d.ts +82 -15
  72. package/lib/garbageCollection.d.ts.map +1 -1
  73. package/lib/garbageCollection.js +361 -28
  74. package/lib/garbageCollection.js.map +1 -1
  75. package/lib/index.d.ts +2 -2
  76. package/lib/index.d.ts.map +1 -1
  77. package/lib/index.js +2 -1
  78. package/lib/index.js.map +1 -1
  79. package/lib/packageVersion.d.ts +1 -1
  80. package/lib/packageVersion.d.ts.map +1 -1
  81. package/lib/packageVersion.js +1 -1
  82. package/lib/packageVersion.js.map +1 -1
  83. package/lib/pendingStateManager.d.ts +0 -1
  84. package/lib/pendingStateManager.d.ts.map +1 -1
  85. package/lib/pendingStateManager.js +0 -36
  86. package/lib/pendingStateManager.js.map +1 -1
  87. package/lib/runningSummarizer.d.ts +3 -2
  88. package/lib/runningSummarizer.d.ts.map +1 -1
  89. package/lib/runningSummarizer.js +6 -6
  90. package/lib/runningSummarizer.js.map +1 -1
  91. package/lib/summarizer.d.ts +23 -3
  92. package/lib/summarizer.d.ts.map +1 -1
  93. package/lib/summarizer.js +135 -45
  94. package/lib/summarizer.js.map +1 -1
  95. package/lib/summarizerTypes.d.ts +3 -10
  96. package/lib/summarizerTypes.d.ts.map +1 -1
  97. package/lib/summarizerTypes.js.map +1 -1
  98. package/lib/summaryFormat.d.ts +10 -1
  99. package/lib/summaryFormat.d.ts.map +1 -1
  100. package/lib/summaryFormat.js +1 -0
  101. package/lib/summaryFormat.js.map +1 -1
  102. package/lib/summaryGenerator.d.ts.map +1 -1
  103. package/lib/summaryGenerator.js +1 -3
  104. package/lib/summaryGenerator.js.map +1 -1
  105. package/lib/summaryManager.d.ts +0 -15
  106. package/lib/summaryManager.d.ts.map +1 -1
  107. package/lib/summaryManager.js +1 -34
  108. package/lib/summaryManager.js.map +1 -1
  109. package/package.json +14 -14
  110. package/src/containerHandleContext.ts +0 -1
  111. package/src/containerRuntime.ts +280 -140
  112. package/src/dataStoreContext.ts +59 -20
  113. package/src/dataStores.ts +116 -54
  114. package/src/garbageCollection.ts +492 -29
  115. package/src/index.ts +20 -2
  116. package/src/packageVersion.ts +1 -1
  117. package/src/pendingStateManager.ts +0 -43
  118. package/src/runningSummarizer.ts +12 -10
  119. package/src/summarizer.ts +154 -53
  120. package/src/summarizerTypes.ts +3 -11
  121. package/src/summaryFormat.ts +11 -1
  122. package/src/summaryGenerator.ts +2 -3
  123. package/src/summaryManager.ts +2 -49
  124. package/dist/localStorageFeatureGates.d.ts +0 -13
  125. package/dist/localStorageFeatureGates.d.ts.map +0 -1
  126. package/dist/localStorageFeatureGates.js +0 -31
  127. package/dist/localStorageFeatureGates.js.map +0 -1
  128. package/lib/localStorageFeatureGates.d.ts +0 -13
  129. package/lib/localStorageFeatureGates.d.ts.map +0 -1
  130. package/lib/localStorageFeatureGates.js +0 -27
  131. package/lib/localStorageFeatureGates.js.map +0 -1
  132. package/src/localStorageFeatureGates.ts +0 -27
@@ -2,34 +2,33 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { AttachState, } from "@fluidframework/container-definitions";
5
+ import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
6
6
  import { assert, Trace, TypedEventEmitter, unreachableCase, performance, } from "@fluidframework/common-utils";
7
- import { ChildLogger, raiseConnectedEvent, PerformanceEvent, normalizeError, TaggedLoggerAdapter, } from "@fluidframework/telemetry-utils";
7
+ import { ChildLogger, raiseConnectedEvent, PerformanceEvent, normalizeError, TaggedLoggerAdapter, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
8
+ import { DriverHeader } from "@fluidframework/driver-definitions";
8
9
  import { readAndParse, BlobAggregationStorage } from "@fluidframework/driver-utils";
9
- import { DataCorruptionError, GenericError, extractSafePropertiesFromMessage } from "@fluidframework/container-utils";
10
- import { BlobTreeEntry, TreeTreeEntry, } from "@fluidframework/protocol-base";
10
+ import { CreateProcessingError, DataCorruptionError, GenericError, UsageError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
11
11
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
12
12
  import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
13
- import { addBlobToSummary, addTreeToSummary, convertToSummaryTree, createRootSummarizerNodeWithGC, FluidSerializer, RequestParser, create404Response, exceptionToResponse, responseToException, seqFromTree, } from "@fluidframework/runtime-utils";
13
+ import { addBlobToSummary, addTreeToSummary, convertToSummaryTree, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, convertSummaryTreeToITree, } from "@fluidframework/runtime-utils";
14
14
  import { v4 as uuid } from "uuid";
15
15
  import { ContainerFluidHandleContext } from "./containerHandleContext";
16
16
  import { FluidDataStoreRegistry } from "./dataStoreRegistry";
17
17
  import { Summarizer } from "./summarizer";
18
- import { formRequestSummarizerFn, SummaryManager } from "./summaryManager";
18
+ import { SummaryManager } from "./summaryManager";
19
19
  import { DeltaScheduler } from "./deltaScheduler";
20
20
  import { ReportOpPerfTelemetry, latencyThreshold } from "./connectionTelemetry";
21
21
  import { PendingStateManager } from "./pendingStateManager";
22
22
  import { pkgVersion } from "./packageVersion";
23
23
  import { BlobManager } from "./blobManager";
24
24
  import { DataStores, getSummaryForDatastores } from "./dataStores";
25
- import { blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./summaryFormat";
25
+ import { aliasBlobName, blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./summaryFormat";
26
26
  import { SummaryCollection } from "./summaryCollection";
27
- import { getLocalStorageFeatureGate } from "./localStorageFeatureGates";
28
27
  import { OrderedClientCollection, OrderedClientElection } from "./orderedClientElection";
29
28
  import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
30
29
  import { formExponentialFn, Throttler } from "./throttler";
31
30
  import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
32
- import { GarbageCollector, } from "./garbageCollection";
31
+ import { GarbageCollector, gcTreeKey, } from "./garbageCollection";
33
32
  export var ContainerMessageType;
34
33
  (function (ContainerMessageType) {
35
34
  // An op to be delivered to store
@@ -42,6 +41,8 @@ export var ContainerMessageType;
42
41
  ContainerMessageType["BlobAttach"] = "blobAttach";
43
42
  // Ties our new clientId to our old one on reconnect
44
43
  ContainerMessageType["Rejoin"] = "rejoin";
44
+ // Sets the alias of a root data store
45
+ ContainerMessageType["Alias"] = "alias";
45
46
  })(ContainerMessageType || (ContainerMessageType = {}));
46
47
  // Consider idle 5s of no activity. And snapshot if a minute has gone by with no snapshot.
47
48
  const IdleDetectionTime = 5000;
@@ -56,12 +57,13 @@ const DefaultSummaryConfiguration = {
56
57
  maxAckWaitTime: 120000,
57
58
  };
58
59
  // Local storage key to set the default flush mode to TurnBased
59
- const turnBasedFlushModeKey = "FluidFlushModeTurnBased";
60
+ const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
60
61
  export function isRuntimeMessage(message) {
61
62
  switch (message.type) {
62
63
  case ContainerMessageType.FluidDataStoreOp:
63
64
  case ContainerMessageType.ChunkedOp:
64
65
  case ContainerMessageType.Attach:
66
+ case ContainerMessageType.Alias:
65
67
  case ContainerMessageType.BlobAttach:
66
68
  case ContainerMessageType.Rejoin:
67
69
  case MessageType.Operation:
@@ -306,13 +308,27 @@ export class ScheduleManager {
306
308
  * ContainerRuntime's perspective.
307
309
  */
308
310
  export const agentSchedulerId = "_scheduler";
311
+ // safely check navigator and get the hardware spec value
312
+ export function getDeviceSpec() {
313
+ try {
314
+ if (typeof navigator === "object" && navigator !== null) {
315
+ return {
316
+ deviceMemory: navigator.deviceMemory,
317
+ hardwareConcurrency: navigator.hardwareConcurrency,
318
+ };
319
+ }
320
+ }
321
+ catch (_a) {
322
+ }
323
+ return {};
324
+ }
309
325
  /**
310
326
  * Represents the runtime of the container. Contains helper functions/state of the container.
311
327
  * It will define the store level mappings.
312
328
  */
313
329
  export class ContainerRuntime extends TypedEventEmitter {
314
- constructor(context, registry, metadata, electedSummarizerData, chunks, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, requestHandler, _storage) {
315
- var _a, _b, _c, _d;
330
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, requestHandler, _storage) {
331
+ var _a, _b, _c, _d, _e;
316
332
  super();
317
333
  this.context = context;
318
334
  this.registry = registry;
@@ -321,14 +337,7 @@ export class ContainerRuntime extends TypedEventEmitter {
321
337
  this.logger = logger;
322
338
  this.requestHandler = requestHandler;
323
339
  this._storage = _storage;
324
- // back-compat: Used by loader in <= 0.35
325
- /**
326
- * @internal
327
- * @deprecated Back-compat only. Used by the loader in versions earlier than 0.35.
328
- */
329
- this.runtimeVersion = pkgVersion;
330
340
  this._orderSequentiallyCalls = 0;
331
- this._flushMode = ContainerRuntime.defaultFlushMode;
332
341
  this.needsFlush = false;
333
342
  this.flushTrigger = false;
334
343
  this.paused = false;
@@ -371,7 +380,7 @@ export class ContainerRuntime extends TypedEventEmitter {
371
380
  // If we're not the summarizer, and we don't have a summaryManager, we expect that
372
381
  // disableSummaries is turned on. We are throwing instead of returning a failure here,
373
382
  // because it is a misuse of the API rather than an expected failure.
374
- throw new Error(`Can't summarize, disableSummaries: ${this.summariesDisabled()}`);
383
+ throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
375
384
  }
376
385
  };
377
386
  this.enqueueSummarize = (...args) => {
@@ -385,18 +394,47 @@ export class ContainerRuntime extends TypedEventEmitter {
385
394
  // If we're not the summarizer, and we don't have a summaryManager, we expect that
386
395
  // generateSummaries is turned off. We are throwing instead of returning a failure here,
387
396
  // because it is a misuse of the API rather than an expected failure.
388
- throw new Error(`Can't summarize, disableSummaries: ${this.summariesDisabled()}`);
397
+ throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
389
398
  }
390
399
  };
391
400
  this.baseSummaryMessage = metadata === null || metadata === void 0 ? void 0 : metadata.message;
401
+ // If this is an existing container, we get values from metadata.
402
+ // otherwise, we initialize them.
403
+ if (existing) {
404
+ this.createContainerMetadata = {
405
+ createContainerRuntimeVersion: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerRuntimeVersion,
406
+ createContainerTimestamp: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerTimestamp,
407
+ };
408
+ this.summaryCount = metadata === null || metadata === void 0 ? void 0 : metadata.summaryCount;
409
+ }
410
+ else {
411
+ this.createContainerMetadata = {
412
+ createContainerRuntimeVersion: pkgVersion,
413
+ createContainerTimestamp: Date.now(),
414
+ };
415
+ }
392
416
  // Default to false (enabled).
393
417
  this.disableIsolatedChannels = (_a = this.runtimeOptions.summaryOptions.disableIsolatedChannels) !== null && _a !== void 0 ? _a : false;
394
418
  this._connected = this.context.connected;
395
419
  this.chunkMap = new Map(chunks);
396
- this.IFluidHandleContext = new ContainerFluidHandleContext("", this);
397
- this.IFluidSerializer = new FluidSerializer(this.IFluidHandleContext);
398
- this._logger = ChildLogger.create(this.logger, "ContainerRuntime");
399
- this.garbageCollector = GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), this._logger, existing, metadata);
420
+ this.handleContext = new ContainerFluidHandleContext("", this);
421
+ this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
422
+ this._flushMode =
423
+ ((_b = this.mc.config.getBoolean(turnBasedFlushModeKey)) !== null && _b !== void 0 ? _b : false) ? FlushMode.TurnBased : FlushMode.Immediate;
424
+ /**
425
+ * Function that return the current server timestamp. This is used by the garbage collector to set the
426
+ * time when a node becomes unreferenced.
427
+ * We use the timestamp of the last op for current timestamp. However, there can be cases where
428
+ * we don't have an op (on demand summaries for instance). In those cases, we will use the timestamp
429
+ * of this client's connection.
430
+ */
431
+ const getCurrentTimestamp = () => {
432
+ var _a, _b, _c;
433
+ const client = this.clientId !== undefined ? this.getAudience().getMember(this.clientId) : undefined;
434
+ const timestamp = client === null || client === void 0 ? void 0 : client.timestamp;
435
+ return (_c = (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : timestamp) !== null && _c !== void 0 ? _c : Date.now();
436
+ };
437
+ this.garbageCollector = GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), getCurrentTimestamp, context.baseSnapshot, async (id) => readAndParse(this.storage, id), this.mc.logger, existing, metadata);
400
438
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
401
439
  this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
402
440
  // Summarize function to call when summarize is called. Summarizer node always tracks summary state.
@@ -413,69 +451,58 @@ export class ContainerRuntime extends TypedEventEmitter {
413
451
  throwOnFailure: true,
414
452
  // If GC should not run, let the summarizer node know so that it does not track GC state.
415
453
  gcDisabled: !this.garbageCollector.shouldRunGC,
416
- // The max duration for which objects can be unreferenced before they are eligible for deletion.
417
- maxUnreferencedDurationMs: this.runtimeOptions.gcOptions.maxUnreferencedDurationMs,
418
454
  });
419
455
  if (this.context.baseSnapshot) {
420
456
  this.summarizerNode.loadBaseSummaryWithoutDifferential(this.context.baseSnapshot);
421
457
  }
422
- this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getInitialGCSummaryDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getInitialGCSummaryDetailsFn), (id) => this.summarizerNode.deleteChild(id), this._logger);
423
- this.blobManager = new BlobManager(this.IFluidHandleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), this, this.logger);
458
+ this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getInitialGCSummaryDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getInitialGCSummaryDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getDataStoreBaseGCDetails(), (id) => this.garbageCollector.nodeChanged(id), new Map(dataStoreAliasMap));
459
+ this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), this, this.logger);
424
460
  this.scheduleManager = new ScheduleManager(context.deltaManager, this, ChildLogger.create(this.logger, "ScheduleManager"));
425
461
  this.deltaSender = this.deltaManager;
426
462
  this.pendingStateManager = new PendingStateManager(this, async (type, content) => this.applyStashedOp(type, content), context.pendingLocalState);
427
463
  this.context.quorum.on("removeMember", (clientId) => {
428
464
  this.clearPartialChunks(clientId);
429
465
  });
430
- this.context.quorum.on("addProposal", (proposal) => {
431
- if (proposal.key === "code" || proposal.key === "code2") {
432
- this.emit("codeDetailsProposed", proposal.value, proposal);
433
- }
434
- });
435
466
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
436
- // Only create a SummaryManager if summaries are enabled and we are not the summarizer client
437
467
  // Map the deprecated generateSummaries flag to disableSummaries.
438
468
  if (this.runtimeOptions.summaryOptions.generateSummaries === false) {
439
469
  this.runtimeOptions.summaryOptions.disableSummaries = true;
440
470
  }
441
- if (this.summariesDisabled()) {
442
- this._logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
471
+ if (this.summariesDisabled) {
472
+ this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
443
473
  }
444
474
  else {
445
- const maxOpsSinceLastSummary = (_b = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _b !== void 0 ? _b : 7000;
446
- const defaultAction = () => {
447
- if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
448
- this.logger.sendErrorEvent({ eventName: "SummaryStatus:Behind" });
449
- // unregister default to no log on every op after falling behind
450
- // and register summary ack handler to re-register this handler
451
- // after successful summary
452
- this.summaryCollection.once(MessageType.SummaryAck, () => {
453
- this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
454
- // we've caught up, so re-register the default action to monitor for
455
- // falling behind, and unregister ourself
456
- this.summaryCollection.on("default", defaultAction);
457
- });
458
- this.summaryCollection.off("default", defaultAction);
459
- }
460
- };
461
- this.summaryCollection.on("default", defaultAction);
462
475
  const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
463
476
  const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
464
477
  const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
465
- const summarizerClientElectionEnabled = (_c = getLocalStorageFeatureGate("summarizerClientElection")) !== null && _c !== void 0 ? _c : ((_d = this.runtimeOptions.summaryOptions) === null || _d === void 0 ? void 0 : _d.summarizerClientElection) === true;
478
+ const summarizerClientElectionEnabled = (_c = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _c !== void 0 ? _c : ((_d = this.runtimeOptions.summaryOptions) === null || _d === void 0 ? void 0 : _d.summarizerClientElection) === true;
479
+ const maxOpsSinceLastSummary = (_e = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _e !== void 0 ? _e : 7000;
466
480
  this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary, summarizerClientElectionEnabled);
467
481
  if (this.context.clientDetails.type === summarizerClientType) {
468
- this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.IFluidHandleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
482
+ this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
469
483
  }
470
484
  else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
471
- // Create the SummaryManager and mark the initial state
472
- const requestOptions = {
473
- cache: false,
474
- reconnect: false,
475
- summarizingClient: true,
485
+ // Only create a SummaryManager and SummarizerClientElection
486
+ // if summaries are enabled and we are not the summarizer client.
487
+ const defaultAction = () => {
488
+ if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
489
+ this.logger.sendErrorEvent({ eventName: "SummaryStatus:Behind" });
490
+ // unregister default to no log on every op after falling behind
491
+ // and register summary ack handler to re-register this handler
492
+ // after successful summary
493
+ this.summaryCollection.once(MessageType.SummaryAck, () => {
494
+ this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
495
+ // we've caught up, so re-register the default action to monitor for
496
+ // falling behind, and unregister ourself
497
+ this.summaryCollection.on("default", defaultAction);
498
+ });
499
+ this.summaryCollection.off("default", defaultAction);
500
+ }
476
501
  };
502
+ this.summaryCollection.on("default", defaultAction);
503
+ // Create the SummaryManager and mark the initial state
477
504
  this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
478
- this.summaryCollection, this.logger, formRequestSummarizerFn(this.context.loader, this.context.deltaManager.lastSequenceNumber, requestOptions), new Throttler(60 * 1000, // 60 sec delay window
505
+ this.summaryCollection, this.logger, this.formRequestSummarizerFn(this.context.loader), new Throttler(60 * 1000, // 60 sec delay window
479
506
  30 * 1000, // 30 sec max delay
480
507
  // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
481
508
  formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
@@ -488,7 +515,7 @@ export class ContainerRuntime extends TypedEventEmitter {
488
515
  this.deltaManager.on("readonly", (readonly) => {
489
516
  // we accumulate ops while being in read-only state.
490
517
  // once user gets write permissions and we have active connection, flush all pending ops.
491
- assert(readonly === this.deltaManager.readonly, 0x124 /* "inconsistent readonly property/event state" */);
518
+ assert(readonly === this.deltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
492
519
  // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
493
520
  // when we either never send an op, or attempted to send it but we know for sure it was not
494
521
  // sequenced by server and will never be sequenced (i.e. was lost)
@@ -507,6 +534,10 @@ export class ContainerRuntime extends TypedEventEmitter {
507
534
  if (context.pendingLocalState !== undefined) {
508
535
  this.deltaManager.on("op", this.onOp);
509
536
  }
537
+ // logging hardware telemetry
538
+ logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
539
+ // logging container load stats
540
+ this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryCount: this.summaryCount, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature }));
510
541
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
511
542
  }
512
543
  get IContainerRuntime() { return this; }
@@ -520,7 +551,7 @@ export class ContainerRuntime extends TypedEventEmitter {
520
551
  * @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
521
552
  */
522
553
  static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing) {
523
- var _a, _b, _c, _d;
554
+ var _a, _b, _c;
524
555
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
525
556
  const passLogger = (_a = context.taggedLogger) !== null && _a !== void 0 ? _a : new TaggedLoggerAdapter(context.logger);
526
557
  const logger = ChildLogger.create(passLogger, undefined, {
@@ -562,19 +593,22 @@ export class ContainerRuntime extends TypedEventEmitter {
562
593
  return readAndParse(storage, blobId);
563
594
  }
564
595
  };
565
- const chunks = (_b = await tryFetchBlob(chunksBlobName)) !== null && _b !== void 0 ? _b : [];
566
- const metadata = await tryFetchBlob(metadataBlobName);
567
- const electedSummarizerData = await tryFetchBlob(electedSummarizerBlobName);
596
+ const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
597
+ tryFetchBlob(chunksBlobName),
598
+ tryFetchBlob(metadataBlobName),
599
+ tryFetchBlob(electedSummarizerBlobName),
600
+ tryFetchBlob(aliasBlobName),
601
+ ]);
568
602
  const loadExisting = existing === true || context.existing === true;
569
603
  // read snapshot blobs needed for BlobManager to load
570
- const blobManagerSnapshot = await BlobManager.load((_c = context.baseSnapshot) === null || _c === void 0 ? void 0 : _c.trees[blobsTreeName], async (id) => {
604
+ const blobManagerSnapshot = await BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[blobsTreeName], async (id) => {
571
605
  // IContainerContext storage api return type still has undefined in 0.39 package version.
572
606
  // So once we release 0.40 container-defn package we can remove this check.
573
607
  assert(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
574
608
  return readAndParse(storage, id);
575
609
  });
576
610
  // Verify summary runtime sequence number matches protocol sequence number.
577
- const runtimeSequenceNumber = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _d === void 0 ? void 0 : _d.sequenceNumber;
611
+ const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
578
612
  if (runtimeSequenceNumber !== undefined) {
579
613
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
580
614
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
@@ -589,13 +623,16 @@ export class ContainerRuntime extends TypedEventEmitter {
589
623
  }
590
624
  }
591
625
  }
592
- const runtime = new ContainerRuntime(context, registry, metadata, electedSummarizerData, chunks, {
626
+ const runtime = new ContainerRuntime(context, registry, metadata, electedSummarizerData, chunks !== null && chunks !== void 0 ? chunks : [], aliases !== null && aliases !== void 0 ? aliases : [], {
593
627
  summaryOptions,
594
628
  gcOptions,
595
629
  loadSequenceNumberVerification,
596
630
  }, containerScope, logger, loadExisting, blobManagerSnapshot, requestHandler, storage);
597
631
  return runtime;
598
632
  }
633
+ /**
634
+ * @deprecated This will be removed in a later release. Deprecated in 0.53
635
+ */
599
636
  get id() {
600
637
  return this.context.id;
601
638
  }
@@ -646,6 +683,9 @@ export class ContainerRuntime extends TypedEventEmitter {
646
683
  get attachState() {
647
684
  return this.context.attachState;
648
685
  }
686
+ get IFluidHandleContext() {
687
+ return this.handleContext;
688
+ }
649
689
  get connected() {
650
690
  return this._connected;
651
691
  }
@@ -659,13 +699,22 @@ export class ContainerRuntime extends TypedEventEmitter {
659
699
  return Object.assign(Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_b = (_a = this.context) === null || _a === void 0 ? void 0 : _a.serviceConfiguration) === null || _b === void 0 ? void 0 : _b.summary), (_c = this.runtimeOptions.summaryOptions) === null || _c === void 0 ? void 0 : _c.summaryConfigOverrides);
660
700
  }
661
701
  get disposed() { return this._disposed; }
662
- static get defaultFlushMode() {
663
- return getLocalStorageFeatureGate(turnBasedFlushModeKey) ? FlushMode.TurnBased : FlushMode.Immediate;
702
+ /**
703
+ * True, if GC data should be written at root of the summary tree.
704
+ * False, if data stores should write GC blobs in their summary tree.
705
+ */
706
+ get writeGCDataAtRoot() {
707
+ return this.garbageCollector.writeDataAtRoot;
664
708
  }
665
709
  get summarizer() {
666
710
  assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
667
711
  return this._summarizer;
668
712
  }
713
+ get summariesDisabled() {
714
+ var _a;
715
+ return this.runtimeOptions.summaryOptions.disableSummaries === true ||
716
+ ((_a = this.runtimeOptions.summaryOptions.summaryConfigOverrides) === null || _a === void 0 ? void 0 : _a.disableSummaries) === true;
717
+ }
669
718
  dispose(error) {
670
719
  var _a;
671
720
  if (this._disposed) {
@@ -779,14 +828,10 @@ export class ContainerRuntime extends TypedEventEmitter {
779
828
  }
780
829
  formMetadata() {
781
830
  var _a;
782
- return {
783
- summaryFormatVersion: 1,
784
- disableIsolatedChannels: this.disableIsolatedChannels || undefined,
785
- gcFeature: this.garbageCollector.gcSummaryFeatureVersion,
831
+ return Object.assign(Object.assign({}, this.createContainerMetadata), { summaryCount: this.summaryCount, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined, gcFeature: this.garbageCollector.gcSummaryFeatureVersion,
786
832
  // The last message processed at the time of summary. If there are no messages, nothing has changed from
787
833
  // the base summary we loaded from. So, use the message from its metadata blob.
788
- message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.baseSummaryMessage,
789
- };
834
+ message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.baseSummaryMessage });
790
835
  }
791
836
  /**
792
837
  * Retrieves the runtime for a data store if it's referenced as per the initially summary that it is loaded with.
@@ -813,22 +858,14 @@ export class ContainerRuntime extends TypedEventEmitter {
813
858
  * @deprecated - Use summarize to get summary of the container runtime.
814
859
  */
815
860
  async snapshot() {
816
- if (this.garbageCollector.shouldRunGC) {
817
- await this.collectGarbage({ logger: this.logger, fullGC: true /* fullGC */ });
818
- }
819
- const root = { entries: [] };
820
- const entries = await this.dataStores.snapshot();
821
- if (this.disableIsolatedChannels) {
822
- root.entries = root.entries.concat(entries);
823
- }
824
- else {
825
- root.entries.push(new TreeTreeEntry(channelsTreeName, { entries }));
826
- }
827
- root.entries.push(new BlobTreeEntry(metadataBlobName, JSON.stringify(this.formMetadata())));
828
- if (this.chunkMap.size > 0) {
829
- root.entries.push(new BlobTreeEntry(chunksBlobName, JSON.stringify([...this.chunkMap])));
830
- }
831
- return root;
861
+ const summaryResult = await this.summarize({
862
+ summaryLogger: this.logger,
863
+ fullTree: true,
864
+ trackState: false,
865
+ runGC: this.garbageCollector.shouldRunGC,
866
+ fullGC: true,
867
+ });
868
+ return convertSummaryTreeToITree(summaryResult.summary);
832
869
  }
833
870
  addContainerBlobsToSummary(summaryTree) {
834
871
  var _a;
@@ -837,6 +874,10 @@ export class ContainerRuntime extends TypedEventEmitter {
837
874
  const content = JSON.stringify([...this.chunkMap]);
838
875
  addBlobToSummary(summaryTree, chunksBlobName, content);
839
876
  }
877
+ const dataStoreAliases = this.dataStores.aliases();
878
+ if (dataStoreAliases.size > 0) {
879
+ addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
880
+ }
840
881
  if (this.summarizerClientElection) {
841
882
  const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
842
883
  addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
@@ -848,6 +889,12 @@ export class ContainerRuntime extends TypedEventEmitter {
848
889
  const blobsTree = convertToSummaryTree(snapshot, false);
849
890
  addTreeToSummary(summaryTree, blobsTreeName, blobsTree);
850
891
  }
892
+ if (this.writeGCDataAtRoot) {
893
+ const gcSummary = this.garbageCollector.summarize();
894
+ if (gcSummary !== undefined) {
895
+ addTreeToSummary(summaryTree, gcTreeKey, gcSummary);
896
+ }
897
+ }
851
898
  }
852
899
  replayPendingStates() {
853
900
  // We need to be able to send ops to replay states
@@ -882,6 +929,7 @@ export class ContainerRuntime extends TypedEventEmitter {
882
929
  return this.dataStores.applyStashedOp(op);
883
930
  case ContainerMessageType.Attach:
884
931
  return this.dataStores.applyStashedAttachOp(op);
932
+ case ContainerMessageType.Alias:
885
933
  case ContainerMessageType.BlobAttach:
886
934
  return;
887
935
  case ContainerMessageType.ChunkedOp:
@@ -903,7 +951,7 @@ export class ContainerRuntime extends TypedEventEmitter {
903
951
  this.replayPendingStates();
904
952
  }
905
953
  this.dataStores.setConnectionState(connected, clientId);
906
- raiseConnectedEvent(this._logger, this, connected, clientId);
954
+ raiseConnectedEvent(this.mc.logger, this, connected, clientId);
907
955
  }
908
956
  process(messageArg, local) {
909
957
  var _a;
@@ -937,6 +985,9 @@ export class ContainerRuntime extends TypedEventEmitter {
937
985
  case ContainerMessageType.Attach:
938
986
  this.dataStores.processAttachMessage(message, local || localAck);
939
987
  break;
988
+ case ContainerMessageType.Alias:
989
+ this.processAliasMessage(message, localOpMetadata, local);
990
+ break;
940
991
  case ContainerMessageType.FluidDataStoreOp:
941
992
  // if localAck === true, treat this as a local op because it's one we sent on a previous container
942
993
  this.dataStores.processFluidDataStoreOp(message, local || localAck, localOpMetadata);
@@ -955,6 +1006,9 @@ export class ContainerRuntime extends TypedEventEmitter {
955
1006
  throw e;
956
1007
  }
957
1008
  }
1009
+ processAliasMessage(message, localOpMetadata, local) {
1010
+ this.dataStores.processAliasMessage(message, localOpMetadata, local);
1011
+ }
958
1012
  processSignal(message, local) {
959
1013
  const envelope = message.content;
960
1014
  const transformed = {
@@ -1004,6 +1058,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1004
1058
  return;
1005
1059
  }
1006
1060
  this.needsFlush = false;
1061
+ // Did we disconnect in the middle of turn-based batch?
1062
+ // If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
1063
+ if (!this.canSendOps()) {
1064
+ return;
1065
+ }
1007
1066
  return this.deltaSender.flush();
1008
1067
  }
1009
1068
  orderSequentially(callback) {
@@ -1020,11 +1079,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1020
1079
  this.setFlushMode(FlushMode.TurnBased);
1021
1080
  try {
1022
1081
  this.trackOrderSequentiallyCalls(callback);
1023
- }
1024
- finally {
1025
1082
  this.flush();
1026
1083
  this.setFlushMode(savedFlushMode);
1027
1084
  }
1085
+ catch (error) {
1086
+ this.closeFn(CreateProcessingError(error, "orderSequentially"));
1087
+ }
1028
1088
  }
1029
1089
  trackOrderSequentiallyCalls(callback) {
1030
1090
  try {
@@ -1180,27 +1240,33 @@ export class ContainerRuntime extends TypedEventEmitter {
1180
1240
  * Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
1181
1241
  * After GC has run, called to notify this container's nodes of routes that are used in it.
1182
1242
  * @param usedRoutes - The routes that are used in all nodes in this Container.
1243
+ * @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes
1244
+ * unreferenced as part of this GC run, this should be used to update the time when it happens.
1183
1245
  * @returns the statistics of the used state of the data stores.
1184
1246
  */
1185
- updateUsedRoutes(usedRoutes) {
1186
- var _a;
1247
+ updateUsedRoutes(usedRoutes, gcTimestamp) {
1187
1248
  // Update our summarizer node's used routes. Updating used routes in summarizer node before
1188
1249
  // summarizing is required and asserted by the the summarizer node. We are the root and are
1189
1250
  // always referenced, so the used routes is only self-route (empty string).
1190
1251
  this.summarizerNode.updateUsedRoutes([""]);
1191
- return this.dataStores.updateUsedRoutes(usedRoutes, (_a =
1192
- // For now, we use the timestamp of the last op for gcTimestamp. However, there can be cases where
1193
- // we don't have an op (on demand summaries for instance). In those cases, we will use the timestamp
1194
- // of this client's connection - https://github.com/microsoft/FluidFramework/issues/7152.
1195
- this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp);
1252
+ return this.dataStores.updateUsedRoutes(usedRoutes, gcTimestamp);
1196
1253
  }
1197
1254
  /**
1198
- * Runs garbage collection and udpates the reference / used state of the nodes in the container.
1255
+ * Runs garbage collection and updates the reference / used state of the nodes in the container.
1199
1256
  * @returns the statistics of the garbage collection run.
1200
1257
  */
1201
1258
  async collectGarbage(options) {
1202
1259
  return this.garbageCollector.collectGarbage(options);
1203
1260
  }
1261
+ /**
1262
+ * Called when a new outbound reference is added to another node. This is used by garbage collection to identify
1263
+ * all references added in the system.
1264
+ * @param srcHandle - The handle of the node that added the reference.
1265
+ * @param outboundHandle - The handle of the outbound node that is referenced.
1266
+ */
1267
+ addedGCOutboundReference(srcHandle, outboundHandle) {
1268
+ this.garbageCollector.addedOutboundReference(srcHandle.absolutePath, outboundHandle.absolutePath);
1269
+ }
1204
1270
  /**
1205
1271
  * Generates the summary tree, uploads it to storage, and then submits the summarize op.
1206
1272
  * This is intended to be called by the summarizer, since it is the implementation of
@@ -1260,6 +1326,13 @@ export class ContainerRuntime extends TypedEventEmitter {
1260
1326
  if (!continueResult.continue) {
1261
1327
  return { stage: "base", referenceSequenceNumber: summaryRefSeqNum, error: continueResult.error };
1262
1328
  }
1329
+ // increment summary count
1330
+ if (this.summaryCount !== undefined) {
1331
+ this.summaryCount++;
1332
+ }
1333
+ else {
1334
+ this.summaryCount = 1;
1335
+ }
1263
1336
  const trace = Trace.start();
1264
1337
  let summarizeResult;
1265
1338
  try {
@@ -1383,10 +1456,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1383
1456
  this.dirtyContainer = dirty;
1384
1457
  if (this.emitDirtyDocumentEvent) {
1385
1458
  this.emit(dirty ? "dirty" : "saved");
1386
- // back-compat: Loader API added in 0.35 only
1387
- if (this.context.updateDirtyContainerState !== undefined) {
1388
- this.context.updateDirtyContainerState(dirty);
1389
- }
1459
+ this.context.updateDirtyContainerState(dirty);
1390
1460
  }
1391
1461
  }
1392
1462
  submitDataStoreOp(id, contents, localOpMetadata = undefined) {
@@ -1467,7 +1537,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1467
1537
  // That might be not what caller hopes to get, but we can look deeper if telemetry tells us it's a problem.
1468
1538
  const middleOfBatch = this.flushMode === FlushMode.TurnBased && this.needsFlush;
1469
1539
  if (middleOfBatch) {
1470
- this._logger.sendErrorEvent({ eventName: "submitSystemMessageError", type });
1540
+ this.mc.logger.sendErrorEvent({ eventName: "submitSystemMessageError", type });
1471
1541
  }
1472
1542
  return this.context.submitFn(type, contents, middleOfBatch);
1473
1543
  }
@@ -1500,6 +1570,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1500
1570
  this.dataStores.resubmitDataStoreOp(content, localOpMetadata);
1501
1571
  break;
1502
1572
  case ContainerMessageType.Attach:
1573
+ case ContainerMessageType.Alias:
1503
1574
  this.submit(type, content, localOpMetadata);
1504
1575
  break;
1505
1576
  case ContainerMessageType.ChunkedOp:
@@ -1531,7 +1602,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1531
1602
  * @returns downloaded snapshot's reference sequence number
1532
1603
  */
1533
1604
  async refreshLatestSummaryAckFromServer(summaryLogger) {
1534
- const snapshot = await this.fetchSnapshotFromStorage(this.id, summaryLogger, {
1605
+ const snapshot = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1535
1606
  eventName: "RefreshLatestSummaryGetSnapshot",
1536
1607
  fetchLatest: true,
1537
1608
  });
@@ -1560,12 +1631,30 @@ export class ContainerRuntime extends TypedEventEmitter {
1560
1631
  return this.pendingStateManager.getLocalState();
1561
1632
  }
1562
1633
  /**
1563
- * @returns true if summaries are explicitly disabled for this ContainerRuntime, false otherwise
1564
- */
1565
- summariesDisabled() {
1566
- var _a;
1567
- return this.runtimeOptions.summaryOptions.disableSummaries === true ||
1568
- ((_a = this.runtimeOptions.summaryOptions.summaryConfigOverrides) === null || _a === void 0 ? void 0 : _a.disableSummaries) === true;
1634
+ * * Forms a function that will request a Summarizer.
1635
+ * @param loaderRouter - the loader acting as an IFluidRouter
1636
+ * */
1637
+ formRequestSummarizerFn(loaderRouter) {
1638
+ return async () => {
1639
+ const request = {
1640
+ headers: {
1641
+ [LoaderHeader.cache]: false,
1642
+ [LoaderHeader.clientDetails]: {
1643
+ capabilities: { interactive: false },
1644
+ type: summarizerClientType,
1645
+ },
1646
+ [DriverHeader.summarizingClient]: true,
1647
+ [LoaderHeader.reconnect]: false,
1648
+ },
1649
+ url: "/_summarizer",
1650
+ };
1651
+ const fluidObject = await requestFluidObject(loaderRouter, request);
1652
+ const summarizer = fluidObject.ISummarizer;
1653
+ if (!summarizer) {
1654
+ throw new UsageError("Fluid object does not implement ISummarizer");
1655
+ }
1656
+ return summarizer;
1657
+ };
1569
1658
  }
1570
1659
  }
1571
1660
  /**