@fluidframework/container-runtime 2.61.0 → 2.62.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 (110) hide show
  1. package/.eslintrc.cjs +4 -72
  2. package/CHANGELOG.md +4 -0
  3. package/container-runtime.test-files.tar +0 -0
  4. package/dist/blobManager/blobManager.d.ts.map +1 -1
  5. package/dist/blobManager/blobManager.js +10 -7
  6. package/dist/blobManager/blobManager.js.map +1 -1
  7. package/dist/blobManager/blobManagerSnapSum.js.map +1 -1
  8. package/dist/channelCollection.js +2 -2
  9. package/dist/channelCollection.js.map +1 -1
  10. package/dist/containerRuntime.d.ts +1 -2
  11. package/dist/containerRuntime.d.ts.map +1 -1
  12. package/dist/containerRuntime.js +93 -96
  13. package/dist/containerRuntime.js.map +1 -1
  14. package/dist/dataStoreContext.d.ts.map +1 -1
  15. package/dist/dataStoreContext.js +2 -2
  16. package/dist/dataStoreContext.js.map +1 -1
  17. package/dist/deltaScheduler.js +1 -1
  18. package/dist/deltaScheduler.js.map +1 -1
  19. package/dist/gc/garbageCollection.d.ts.map +1 -1
  20. package/dist/gc/garbageCollection.js +3 -1
  21. package/dist/gc/garbageCollection.js.map +1 -1
  22. package/dist/gc/gcConfigs.js +3 -1
  23. package/dist/gc/gcConfigs.js.map +1 -1
  24. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -1
  25. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  26. package/dist/gc/gcTelemetry.js +4 -3
  27. package/dist/gc/gcTelemetry.js.map +1 -1
  28. package/dist/inboundBatchAggregator.js +1 -1
  29. package/dist/inboundBatchAggregator.js.map +1 -1
  30. package/dist/metadata.d.ts.map +1 -1
  31. package/dist/metadata.js +2 -1
  32. package/dist/metadata.js.map +1 -1
  33. package/dist/opLifecycle/opGroupingManager.js +2 -2
  34. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  35. package/dist/packageVersion.d.ts +1 -1
  36. package/dist/packageVersion.js +1 -1
  37. package/dist/packageVersion.js.map +1 -1
  38. package/dist/pendingStateManager.d.ts.map +1 -1
  39. package/dist/pendingStateManager.js +8 -3
  40. package/dist/pendingStateManager.js.map +1 -1
  41. package/dist/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -1
  42. package/dist/summary/summaryDelayLoadedModule/runningSummarizer.js +3 -2
  43. package/dist/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -1
  44. package/dist/summary/summaryDelayLoadedModule/summarizer.js +1 -1
  45. package/dist/summary/summaryDelayLoadedModule/summarizer.js.map +1 -1
  46. package/dist/summary/summaryDelayLoadedModule/summaryGenerator.js +1 -1
  47. package/dist/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -1
  48. package/lib/blobManager/blobManager.d.ts.map +1 -1
  49. package/lib/blobManager/blobManager.js +10 -7
  50. package/lib/blobManager/blobManager.js.map +1 -1
  51. package/lib/blobManager/blobManagerSnapSum.js.map +1 -1
  52. package/lib/channelCollection.js +2 -2
  53. package/lib/channelCollection.js.map +1 -1
  54. package/lib/containerRuntime.d.ts +1 -2
  55. package/lib/containerRuntime.d.ts.map +1 -1
  56. package/lib/containerRuntime.js +22 -25
  57. package/lib/containerRuntime.js.map +1 -1
  58. package/lib/dataStoreContext.d.ts.map +1 -1
  59. package/lib/dataStoreContext.js +2 -2
  60. package/lib/dataStoreContext.js.map +1 -1
  61. package/lib/deltaScheduler.js +1 -1
  62. package/lib/deltaScheduler.js.map +1 -1
  63. package/lib/gc/garbageCollection.d.ts.map +1 -1
  64. package/lib/gc/garbageCollection.js +3 -1
  65. package/lib/gc/garbageCollection.js.map +1 -1
  66. package/lib/gc/gcConfigs.js +3 -1
  67. package/lib/gc/gcConfigs.js.map +1 -1
  68. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -1
  69. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  70. package/lib/gc/gcTelemetry.js +4 -3
  71. package/lib/gc/gcTelemetry.js.map +1 -1
  72. package/lib/inboundBatchAggregator.js +1 -1
  73. package/lib/inboundBatchAggregator.js.map +1 -1
  74. package/lib/metadata.d.ts.map +1 -1
  75. package/lib/metadata.js +2 -1
  76. package/lib/metadata.js.map +1 -1
  77. package/lib/opLifecycle/opGroupingManager.js +2 -2
  78. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  79. package/lib/packageVersion.d.ts +1 -1
  80. package/lib/packageVersion.js +1 -1
  81. package/lib/packageVersion.js.map +1 -1
  82. package/lib/pendingStateManager.d.ts.map +1 -1
  83. package/lib/pendingStateManager.js +8 -3
  84. package/lib/pendingStateManager.js.map +1 -1
  85. package/lib/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -1
  86. package/lib/summary/summaryDelayLoadedModule/runningSummarizer.js +3 -2
  87. package/lib/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -1
  88. package/lib/summary/summaryDelayLoadedModule/summarizer.js +1 -1
  89. package/lib/summary/summaryDelayLoadedModule/summarizer.js.map +1 -1
  90. package/lib/summary/summaryDelayLoadedModule/summaryGenerator.js +1 -1
  91. package/lib/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -1
  92. package/package.json +18 -18
  93. package/src/blobManager/blobManager.ts +12 -7
  94. package/src/blobManager/blobManagerSnapSum.ts +1 -1
  95. package/src/channelCollection.ts +3 -3
  96. package/src/containerRuntime.ts +58 -65
  97. package/src/dataStoreContext.ts +3 -3
  98. package/src/deltaScheduler.ts +1 -1
  99. package/src/gc/garbageCollection.ts +5 -2
  100. package/src/gc/gcConfigs.ts +3 -3
  101. package/src/gc/gcReferenceGraphAlgorithm.ts +1 -1
  102. package/src/gc/gcTelemetry.ts +4 -5
  103. package/src/inboundBatchAggregator.ts +1 -1
  104. package/src/metadata.ts +2 -1
  105. package/src/opLifecycle/opGroupingManager.ts +2 -2
  106. package/src/packageVersion.ts +1 -1
  107. package/src/pendingStateManager.ts +11 -5
  108. package/src/summary/summaryDelayLoadedModule/runningSummarizer.ts +3 -2
  109. package/src/summary/summaryDelayLoadedModule/summarizer.ts +1 -1
  110. package/src/summary/summaryDelayLoadedModule/summaryGenerator.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.61.0",
3
+ "version": "2.62.0",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -119,18 +119,18 @@
119
119
  "temp-directory": "nyc/.nyc_output"
120
120
  },
121
121
  "dependencies": {
122
- "@fluid-internal/client-utils": "~2.61.0",
123
- "@fluidframework/container-definitions": "~2.61.0",
124
- "@fluidframework/container-runtime-definitions": "~2.61.0",
125
- "@fluidframework/core-interfaces": "~2.61.0",
126
- "@fluidframework/core-utils": "~2.61.0",
127
- "@fluidframework/datastore": "~2.61.0",
128
- "@fluidframework/driver-definitions": "~2.61.0",
129
- "@fluidframework/driver-utils": "~2.61.0",
130
- "@fluidframework/id-compressor": "~2.61.0",
131
- "@fluidframework/runtime-definitions": "~2.61.0",
132
- "@fluidframework/runtime-utils": "~2.61.0",
133
- "@fluidframework/telemetry-utils": "~2.61.0",
122
+ "@fluid-internal/client-utils": "~2.62.0",
123
+ "@fluidframework/container-definitions": "~2.62.0",
124
+ "@fluidframework/container-runtime-definitions": "~2.62.0",
125
+ "@fluidframework/core-interfaces": "~2.62.0",
126
+ "@fluidframework/core-utils": "~2.62.0",
127
+ "@fluidframework/datastore": "~2.62.0",
128
+ "@fluidframework/driver-definitions": "~2.62.0",
129
+ "@fluidframework/driver-utils": "~2.62.0",
130
+ "@fluidframework/id-compressor": "~2.62.0",
131
+ "@fluidframework/runtime-definitions": "~2.62.0",
132
+ "@fluidframework/runtime-utils": "~2.62.0",
133
+ "@fluidframework/telemetry-utils": "~2.62.0",
134
134
  "@tylerbu/sorted-btree-es6": "^1.8.0",
135
135
  "double-ended-queue": "^2.1.0-0",
136
136
  "lz4js": "^0.2.0",
@@ -140,16 +140,16 @@
140
140
  "devDependencies": {
141
141
  "@arethetypeswrong/cli": "^0.17.1",
142
142
  "@biomejs/biome": "~1.9.3",
143
- "@fluid-internal/mocha-test-setup": "~2.61.0",
144
- "@fluid-private/stochastic-test-utils": "~2.61.0",
145
- "@fluid-private/test-pairwise-generator": "~2.61.0",
143
+ "@fluid-internal/mocha-test-setup": "~2.62.0",
144
+ "@fluid-private/stochastic-test-utils": "~2.62.0",
145
+ "@fluid-private/test-pairwise-generator": "~2.62.0",
146
146
  "@fluid-tools/benchmark": "^0.51.0",
147
147
  "@fluid-tools/build-cli": "^0.58.3",
148
148
  "@fluidframework/build-common": "^2.0.3",
149
149
  "@fluidframework/build-tools": "^0.58.3",
150
150
  "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.60.0",
151
151
  "@fluidframework/eslint-config-fluid": "^6.0.0",
152
- "@fluidframework/test-runtime-utils": "~2.61.0",
152
+ "@fluidframework/test-runtime-utils": "~2.62.0",
153
153
  "@microsoft/api-extractor": "7.52.11",
154
154
  "@types/double-ended-queue": "^2.1.0",
155
155
  "@types/lz4js": "^0.2.0",
@@ -213,7 +213,7 @@
213
213
  "test:benchmark:report": "cross-env \"MOCHA_SPEC=dist/**/*.perf.spec.*js\" mocha --timeout 10s --perfMode --parentProcess --fgrep @Benchmark --fgrep @ExecutionTime --reporter @fluid-tools/benchmark/dist/MochaReporter.js",
214
214
  "test:coverage": "c8 npm test",
215
215
  "test:mocha": "npm run test:mocha:esm && echo skipping cjs to avoid overhead - npm run test:mocha:cjs",
216
- "test:mocha:cjs": "cross-env MOCHA_SPEC=dist/test mocha",
216
+ "test:mocha:cjs": "cross-env FLUID_TEST_MODULE_SYSTEM=CJS mocha",
217
217
  "test:mocha:esm": "mocha",
218
218
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
219
219
  "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && npm run place:cjs:package-stub",
@@ -274,7 +274,10 @@ export class BlobManager {
274
274
  pendingEntry !== undefined,
275
275
  0x725 /* Must have pending blob entry for upcoming op */,
276
276
  );
277
- if (pendingEntry?.uploadTime && pendingEntry?.minTTLInSeconds) {
277
+ if (
278
+ pendingEntry?.uploadTime !== undefined &&
279
+ pendingEntry?.minTTLInSeconds !== undefined
280
+ ) {
278
281
  const secondsSinceUpload = (Date.now() - pendingEntry.uploadTime) / 1000;
279
282
  const expired = pendingEntry.minTTLInSeconds - secondsSinceUpload < 0;
280
283
  this.mc.logger.sendTelemetryEvent({
@@ -376,6 +379,8 @@ export class BlobManager {
376
379
  // eventually and wait. We do this even if the local client doesn't have the blob payloadPending flag
377
380
  // enabled, in case a remote client does have it enabled. This wait may be infinite if the uploading
378
381
  // client failed the upload and doesn't exist anymore.
382
+ // TODO: Fix this violation and remove the disable
383
+ // eslint-disable-next-line require-atomic-updates
379
384
  storageId = await new Promise<string>((resolve) => {
380
385
  const onProcessBlobAttach = (_localId: string, _storageId: string): void => {
381
386
  if (_localId === localId) {
@@ -466,7 +471,7 @@ export class BlobManager {
466
471
  blob: ArrayBufferLike,
467
472
  signal?: AbortSignal,
468
473
  ): Promise<IFluidHandleInternalPayloadPending<ArrayBufferLike>> {
469
- if (signal?.aborted) {
474
+ if (signal?.aborted === true) {
470
475
  throw this.createAbortError();
471
476
  }
472
477
 
@@ -485,7 +490,7 @@ export class BlobManager {
485
490
  this.pendingBlobs.set(localId, pendingEntry);
486
491
 
487
492
  const abortListener = (): void => {
488
- if (!pendingEntry.acked) {
493
+ if (pendingEntry.acked !== true) {
489
494
  pendingEntry.handleP.reject(this.createAbortError(pendingEntry));
490
495
  }
491
496
  };
@@ -593,7 +598,7 @@ export class BlobManager {
593
598
  private deletePendingBlobMaybe(localId: string): void {
594
599
  if (this.pendingBlobs.has(localId)) {
595
600
  const entry = this.pendingBlobs.get(localId);
596
- if (entry?.attached && entry?.acked) {
601
+ if (entry?.attached === true && entry?.acked === true) {
597
602
  this.deletePendingBlob(localId);
598
603
  }
599
604
  }
@@ -612,7 +617,7 @@ export class BlobManager {
612
617
  const entry = this.pendingBlobs.get(localId);
613
618
 
614
619
  assert(entry !== undefined, 0x6c8 /* pending blob entry not found for uploaded blob */);
615
- if (entry.abortSignal?.aborted === true && !entry.opsent) {
620
+ if (entry.abortSignal?.aborted === true && entry.opsent !== true) {
616
621
  this.mc.logger.sendTelemetryEvent({
617
622
  eventName: "BlobAborted",
618
623
  localId,
@@ -632,7 +637,7 @@ export class BlobManager {
632
637
  // until its storage ID is added to the next summary.
633
638
  // 2. It will create a local ID to storage ID mapping in all clients which is needed to retrieve the
634
639
  // blob from the server via the storage ID.
635
- if (!entry.opsent) {
640
+ if (entry.opsent !== true) {
636
641
  this.sendBlobAttachOp(localId, response.id);
637
642
  }
638
643
  const storageIds = getStorageIds(this.redirectTable);
@@ -687,7 +692,7 @@ export class BlobManager {
687
692
  );
688
693
  const { localId, blobId: storageId } = message.metadata;
689
694
  const pendingEntry = this.pendingBlobs.get(localId);
690
- if (pendingEntry?.abortSignal?.aborted) {
695
+ if (pendingEntry?.abortSignal?.aborted === true) {
691
696
  this.deletePendingBlob(localId);
692
697
  return;
693
698
  }
@@ -42,7 +42,7 @@ const loadV1 = async (
42
42
  return {};
43
43
  }
44
44
  let redirectTableEntries: [string, string][] = [];
45
- const tableId = blobsTree.blobs[redirectTableBlobName];
45
+ const tableId: string | undefined = blobsTree.blobs[redirectTableBlobName];
46
46
  if (tableId) {
47
47
  redirectTableEntries = await readAndParse(context.storage, tableId);
48
48
  }
@@ -545,7 +545,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
545
545
 
546
546
  // If message timestamp doesn't exist, this is called in a detached container. Don't notify GC in that case
547
547
  // because it doesn't run in detached container and doesn't need to know about this route.
548
- if (messageTimestampMs) {
548
+ if (messageTimestampMs !== undefined) {
549
549
  this.parentContext.addedGCOutboundRoute("/", `/${internalId}`, messageTimestampMs);
550
550
  }
551
551
 
@@ -1613,8 +1613,8 @@ export function getSummaryForDatastores(
1613
1613
  }
1614
1614
 
1615
1615
  if (rootHasIsolatedChannels(metadata)) {
1616
- const datastoresSnapshot = snapshot.trees[channelsTreeName];
1617
- assert(!!datastoresSnapshot, 0x168 /* Expected tree in snapshot not found */);
1616
+ const datastoresSnapshot: ISnapshotTree | undefined = snapshot.trees[channelsTreeName];
1617
+ assert(datastoresSnapshot !== undefined, 0x168 /* Expected tree in snapshot not found */);
1618
1618
  return datastoresSnapshot;
1619
1619
  } else {
1620
1620
  // back-compat: strip out all non-datastore paths before giving to DataStores object.
@@ -83,6 +83,7 @@ import type {
83
83
  ISnapshotTree,
84
84
  ISummaryContent,
85
85
  ISummaryContext,
86
+ SummaryObject,
86
87
  } from "@fluidframework/driver-definitions/internal";
87
88
  import { FetchSource, MessageType } from "@fluidframework/driver-definitions/internal";
88
89
  import { readAndParse } from "@fluidframework/driver-utils/internal";
@@ -128,22 +129,20 @@ import type {
128
129
  MinimumVersionForCollab,
129
130
  } from "@fluidframework/runtime-definitions/internal";
130
131
  import {
131
- defaultMinVersionForCollab,
132
- isValidMinVersionForCollab,
133
- } from "@fluidframework/runtime-utils/internal";
134
- import {
135
- GCDataBuilder,
136
- RequestParser,
137
- RuntimeHeaders,
138
- TelemetryContext,
139
132
  addBlobToSummary,
140
133
  addSummarizeResultToSummary,
141
134
  calculateStats,
142
135
  create404Response,
136
+ defaultMinVersionForCollab,
143
137
  exceptionToResponse,
138
+ GCDataBuilder,
139
+ isValidMinVersionForCollab,
140
+ RequestParser,
141
+ RuntimeHeaders,
142
+ semanticVersionToMinimumVersionForCollab,
144
143
  seqFromTree,
144
+ TelemetryContext,
145
145
  } from "@fluidframework/runtime-utils/internal";
146
- import { semanticVersionToMinimumVersionForCollab } from "@fluidframework/runtime-utils/internal";
147
146
  import type {
148
147
  IEventSampler,
149
148
  IFluidErrorBase,
@@ -257,56 +256,54 @@ import {
257
256
  } from "./runtimeLayerCompatState.js";
258
257
  import { SignalTelemetryManager } from "./signalTelemetryProcessing.js";
259
258
  // These types are imported as types here because they are present in summaryDelayLoadedModule, which is loaded dynamically when required.
260
- import type {
261
- IDocumentSchemaChangeMessageIncoming,
262
- IDocumentSchemaCurrent,
263
- Summarizer,
264
- IDocumentSchemaFeatures,
265
- EnqueueSummarizeResult,
266
- ISerializedElection,
267
- ISummarizeResults,
268
- } from "./summary/index.js";
269
259
  import {
260
+ aliasBlobName,
261
+ chunksBlobName,
262
+ createRootSummarizerNodeWithGC,
263
+ DefaultSummaryConfiguration,
270
264
  DocumentsSchemaController,
265
+ electedSummarizerBlobName,
266
+ type EnqueueSummarizeResult,
267
+ extractSummaryMetadataMessage,
268
+ formCreateSummarizerFn,
271
269
  type IBaseSummarizeResult,
272
270
  type IConnectableRuntime,
273
271
  type IContainerRuntimeMetadata,
274
272
  type ICreateContainerMetadata,
273
+ idCompressorBlobName,
274
+ type IdCompressorMode,
275
+ type IDocumentSchemaChangeMessageIncoming,
276
+ type IDocumentSchemaCurrent,
277
+ type IDocumentSchemaFeatures,
275
278
  type IEnqueueSummarizeOptions,
276
- type IGenerateSummaryTreeResult,
277
279
  type IGeneratedSummaryStats,
280
+ type IGenerateSummaryTreeResult,
278
281
  type IOnDemandSummarizeOptions,
279
282
  type IRefreshSummaryAckOptions,
280
283
  type IRootSummarizerNodeWithGC,
284
+ type ISerializedElection,
285
+ isSummariesDisabled,
281
286
  type ISubmitSummaryOptions,
287
+ type ISummarizeResults,
282
288
  type ISummarizerInternalsProvider,
283
289
  type ISummarizerRuntime,
290
+ type ISummaryConfiguration,
284
291
  type ISummaryMetadataMessage,
285
- type IdCompressorMode,
292
+ metadataBlobName,
293
+ OrderedClientCollection,
286
294
  OrderedClientElection,
287
- RetriableSummaryError,
288
- type SubmitSummaryResult,
289
- aliasBlobName,
290
- chunksBlobName,
291
295
  recentBatchInfoBlobName,
292
- createRootSummarizerNodeWithGC,
293
- electedSummarizerBlobName,
294
- extractSummaryMetadataMessage,
295
- idCompressorBlobName,
296
- metadataBlobName,
296
+ RetriableSummaryError,
297
297
  rootHasIsolatedChannels,
298
- wrapSummaryInChannelsTree,
299
- formCreateSummarizerFn,
300
- summarizerRequestUrl,
301
- SummaryManager,
298
+ type SubmitSummaryResult,
299
+ type Summarizer,
302
300
  SummarizerClientElection,
301
+ summarizerClientType,
302
+ summarizerRequestUrl,
303
303
  SummaryCollection,
304
- OrderedClientCollection,
304
+ SummaryManager,
305
305
  validateSummaryHeuristicConfiguration,
306
- type ISummaryConfiguration,
307
- DefaultSummaryConfiguration,
308
- isSummariesDisabled,
309
- summarizerClientType,
306
+ wrapSummaryInChannelsTree,
310
307
  } from "./summary/index.js";
311
308
  import { Throttler, formExponentialFn } from "./throttler.js";
312
309
 
@@ -682,7 +679,7 @@ export const makeLegacySendBatchFn =
682
679
  function lastMessageFromMetadata(
683
680
  metadata: IContainerRuntimeMetadata | undefined,
684
681
  ): ISummaryMetadataMessage | undefined {
685
- return metadata?.documentSchema?.runtime?.explicitSchemaControl
682
+ return metadata?.documentSchema?.runtime?.explicitSchemaControl === true
686
683
  ? metadata?.lastMessage
687
684
  : metadata?.message;
688
685
  }
@@ -973,7 +970,7 @@ export class ContainerRuntime
973
970
 
974
971
  const tryFetchBlob = async <T>(blobName: string): Promise<T | undefined> => {
975
972
  const blobId = context.baseSnapshot?.blobs[blobName];
976
- if (context.baseSnapshot && blobId) {
973
+ if (context.baseSnapshot !== undefined && blobId !== undefined) {
977
974
  // IContainerContext storage api return type still has undefined in 0.39 package version.
978
975
  // So once we release 0.40 container-defn package we can remove this check.
979
976
  assert(
@@ -1013,7 +1010,7 @@ export class ContainerRuntime
1013
1010
  const runtimeSequenceNumber = messageAtLastSummary?.sequenceNumber;
1014
1011
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
1015
1012
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
1016
- if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
1013
+ if (context.pendingLocalState === undefined && runtimeSequenceNumber !== undefined) {
1017
1014
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
1018
1015
  // eslint-disable-next-line unicorn/no-lonely-if -- Separate if statements make flow easier to parse
1019
1016
  if (
@@ -1463,7 +1460,7 @@ export class ContainerRuntime
1463
1460
  */
1464
1461
  private readonly loadedFromVersionId: string | undefined;
1465
1462
 
1466
- private readonly isSnapshotInstanceOfISnapshot: boolean | undefined;
1463
+ private readonly isSnapshotInstanceOfISnapshot: boolean;
1467
1464
 
1468
1465
  /**
1469
1466
  * The summary context of the last acked summary. The properties from this as used when uploading a summary.
@@ -1559,6 +1556,8 @@ export class ContainerRuntime
1559
1556
  // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
1560
1557
  this.disposeFn = disposeFn ?? closeFn;
1561
1558
 
1559
+ this.isSnapshotInstanceOfISnapshot = snapshotWithContents !== undefined;
1560
+
1562
1561
  // Validate that the Loader is compatible with this Runtime.
1563
1562
  const maybeLoaderCompatDetailsForRuntime = context as FluidObject<ILayerCompatDetails>;
1564
1563
  validateLoaderCompatibility(
@@ -1607,7 +1606,7 @@ export class ContainerRuntime
1607
1606
  submitSignalFn(envelope, targetClientId);
1608
1607
  };
1609
1608
  this.submitSignalFn = (envelope: UnsequencedSignalEnvelope, targetClientId?: string) => {
1610
- if (envelope.address?.startsWith("/")) {
1609
+ if (envelope.address?.startsWith("/") === true) {
1611
1610
  throw new Error("General path based addressing is not implemented");
1612
1611
  }
1613
1612
  sequenceAndSubmitSignal(envelope, targetClientId);
@@ -1874,10 +1873,6 @@ export class ContainerRuntime
1874
1873
 
1875
1874
  const parentContext = wrapContext(this);
1876
1875
 
1877
- if (snapshotWithContents !== undefined) {
1878
- this.isSnapshotInstanceOfISnapshot = true;
1879
- }
1880
-
1881
1876
  // Due to a mismatch between different layers in terms of
1882
1877
  // what is the interface of passing signals, we need the
1883
1878
  // downstream stores to wrap the signal.
@@ -2548,7 +2543,7 @@ export class ContainerRuntime
2548
2543
  );
2549
2544
 
2550
2545
  // Is document schema explicit control on?
2551
- const explicitSchemaControl = documentSchema?.runtime.explicitSchemaControl;
2546
+ const explicitSchemaControl = documentSchema?.runtime.explicitSchemaControl === true;
2552
2547
 
2553
2548
  const metadata: IContainerRuntimeMetadata = {
2554
2549
  ...this.createContainerMetadata,
@@ -2559,7 +2554,7 @@ export class ContainerRuntime
2559
2554
  telemetryDocumentId: this.telemetryDocumentId,
2560
2555
  // If explicit document schema control is not on, use legacy way to supply last message (using 'message' property).
2561
2556
  // Otherwise use new 'lastMessage' property, but also put content into the 'message' property that cases old
2562
- // runtimes (that preceed document schema control capabilities) to close container on load due to mismatch in
2557
+ // runtimes (that preceded document schema control capabilities) to close container on load due to mismatch in
2563
2558
  // last message's sequence number.
2564
2559
  // See also lastMessageFromMetadata()
2565
2560
  message: explicitSchemaControl
@@ -2960,7 +2955,7 @@ export class ContainerRuntime
2960
2955
  if ("batchStart" in inboundResult) {
2961
2956
  const batchStart: BatchStartInfo = inboundResult.batchStart;
2962
2957
  const result = this.duplicateBatchDetector?.processInboundBatch(batchStart);
2963
- if (result?.duplicate) {
2958
+ if (result?.duplicate === true) {
2964
2959
  const error = new DataCorruptionError(
2965
2960
  "Duplicate batch - The same batch was sequenced twice",
2966
2961
  { batchId: batchStart.batchId },
@@ -3430,7 +3425,7 @@ export class ContainerRuntime
3430
3425
  let checkpoint: IBatchCheckpoint | undefined;
3431
3426
  // eslint-disable-next-line import/no-deprecated
3432
3427
  let stageControls: StageControlsExperimental | undefined;
3433
- if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
3428
+ if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback") === true) {
3434
3429
  if (!this.batchRunner.running && !this.inStagingMode) {
3435
3430
  stageControls = this.enterStagingMode();
3436
3431
  }
@@ -3640,7 +3635,7 @@ export class ContainerRuntime
3640
3635
  private shouldSendOps(): boolean {
3641
3636
  // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
3642
3637
  // container runtime's ability to send ops depend on the actual readonly state of the delta manager.
3643
- return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
3638
+ return this.connected && this.innerDeltaManager.readOnlyInfo.readonly !== true;
3644
3639
  }
3645
3640
 
3646
3641
  private readonly _quorum: IQuorumClients;
@@ -4299,15 +4294,16 @@ export class ContainerRuntime
4299
4294
  // Counting dataStores and handles
4300
4295
  // Because handles are unchanged dataStores in the current logic,
4301
4296
  // summarized dataStore count is total dataStore count minus handle count
4302
- const dataStoreTree = summaryTree.tree[channelsTreeName];
4297
+ const dataStoreTree: SummaryObject | undefined = summaryTree.tree[channelsTreeName];
4303
4298
 
4304
- assert(dataStoreTree.type === SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
4299
+ assert(dataStoreTree?.type === SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
4305
4300
  const handleCount = Object.values(dataStoreTree.tree).filter(
4306
4301
  (value) => value.type === SummaryType.Handle,
4307
4302
  ).length;
4308
- const gcSummaryTreeStats = summaryTree.tree[gcTreeKey]
4309
- ? calculateStats(summaryTree.tree[gcTreeKey])
4310
- : undefined;
4303
+ const gcSummaryTreeStats =
4304
+ summaryTree.tree[gcTreeKey] === undefined
4305
+ ? undefined
4306
+ : calculateStats(summaryTree.tree[gcTreeKey]);
4311
4307
 
4312
4308
  const summaryStats: IGeneratedSummaryStats = {
4313
4309
  dataStoreCount: this.channelCollection.size,
@@ -4358,7 +4354,7 @@ export class ContainerRuntime
4358
4354
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4359
4355
  head: parent!,
4360
4356
  message,
4361
- parents: parent ? [parent] : [],
4357
+ parents: parent === undefined ? [] : [parent],
4362
4358
  };
4363
4359
  const uploadData = {
4364
4360
  ...generateSummaryData,
@@ -4444,7 +4440,7 @@ export class ContainerRuntime
4444
4440
  // the summarizer.
4445
4441
  if (
4446
4442
  finalAttempt &&
4447
- this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")
4443
+ this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary") === true
4448
4444
  ) {
4449
4445
  const error = DataProcessingError.create(
4450
4446
  "Pending ops during summarization",
@@ -4599,7 +4595,7 @@ export class ContainerRuntime
4599
4595
 
4600
4596
  // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
4601
4597
  // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
4602
- if (this.innerDeltaManager.readOnlyInfo.readonly) {
4598
+ if (this.innerDeltaManager.readOnlyInfo.readonly === true) {
4603
4599
  this.mc.logger.sendTelemetryEvent({
4604
4600
  eventName: "SubmitOpInReadonly",
4605
4601
  connected: this.connected,
@@ -5031,10 +5027,7 @@ export class ContainerRuntime
5031
5027
  scenarioName,
5032
5028
  FetchSource.noCache,
5033
5029
  );
5034
- assert(
5035
- !!versions && !!versions[0],
5036
- 0x137 /* "Failed to get version from storage" */,
5037
- );
5030
+ assert(versions[0] !== undefined, 0x137 /* "Failed to get version from storage" */);
5038
5031
  snapshotTree = await this.storage.getSnapshotTree(versions[0]);
5039
5032
  assert(!!snapshotTree, 0x138 /* "Failed to get snapshot from storage" */);
5040
5033
  props.snapshotVersion = versions[0].id;
@@ -5070,7 +5063,7 @@ export class ContainerRuntime
5070
5063
  }
5071
5064
 
5072
5065
  this.verifyNotClosed();
5073
- if (props?.notifyImminentClosure) {
5066
+ if (props?.notifyImminentClosure === true) {
5074
5067
  throw new UsageError("notifyImminentClosure is no longer supported in ContainerRuntime");
5075
5068
  }
5076
5069
 
@@ -282,7 +282,7 @@ export abstract class FluidDataStoreContext
282
282
 
283
283
  private isStagingMode: boolean = false;
284
284
  public isReadOnly = (): boolean =>
285
- (this.isStagingMode && this.channel?.policies?.readonlyInStagingMode !== false) ||
285
+ (this.isStagingMode && this.channel?.policies?.readonlyInStagingMode === true) ||
286
286
  this.parentContext.isReadOnly();
287
287
 
288
288
  public get connected(): boolean {
@@ -1231,7 +1231,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
1231
1231
  private snapshotFetchRequired: boolean | undefined;
1232
1232
  private readonly runtime: IContainerRuntimeBase;
1233
1233
  private readonly blobContents: Map<string, ArrayBuffer> | undefined;
1234
- private readonly isSnapshotInISnapshotFormat: boolean | undefined;
1234
+ private readonly isSnapshotInISnapshotFormat: boolean;
1235
1235
 
1236
1236
  constructor(props: IRemoteFluidDataStoreContextProps) {
1237
1237
  super(props, true /* existing */, false /* isLocalDataStore */, () => {
@@ -1290,7 +1290,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
1290
1290
  this.blobContents,
1291
1291
  );
1292
1292
  }
1293
- if (this.snapshotFetchRequired) {
1293
+ if (this.snapshotFetchRequired === true) {
1294
1294
  assert(
1295
1295
  this.loadingGroupId !== undefined,
1296
1296
  0x8f5 /* groupId should be present to fetch snapshot */,
@@ -69,7 +69,7 @@ export class DeltaScheduler {
69
69
  }
70
70
 
71
71
  private readonly batchBegin = (message: ISequencedDocumentMessage): void => {
72
- if (!this.processingStartTime) {
72
+ if (this.processingStartTime === undefined) {
73
73
  this.processingStartTime = performanceNow();
74
74
  }
75
75
  if (this.schedulingLog === undefined && this.schedulingCount % 500 === 0) {
@@ -5,6 +5,7 @@
5
5
 
6
6
  import type { IRequest } from "@fluidframework/core-interfaces";
7
7
  import { assert, LazyPromise, Timer } from "@fluidframework/core-utils/internal";
8
+ import type { ISnapshotTree } from "@fluidframework/driver-definitions/internal";
8
9
  import {
9
10
  type IGarbageCollectionDetailsBase,
10
11
  type ISummarizeResult,
@@ -190,7 +191,7 @@ export class GarbageCollector implements IGarbageCollector {
190
191
  );
191
192
  let timeoutMs = this.configs.sessionExpiryTimeoutMs;
192
193
 
193
- if (pendingSessionExpiryTimerStarted) {
194
+ if (pendingSessionExpiryTimerStarted !== undefined) {
194
195
  // NOTE: This assumes the client clock hasn't been tampered with since the original session
195
196
  const timeLapsedSincePendingTimer = Date.now() - pendingSessionExpiryTimerStarted;
196
197
  timeoutMs -= timeLapsedSincePendingTimer;
@@ -232,7 +233,7 @@ export class GarbageCollector implements IGarbageCollector {
232
233
 
233
234
  try {
234
235
  // For newer documents, GC data should be present in the GC tree in the root of the snapshot.
235
- const gcSnapshotTree = baseSnapshot.trees[gcTreeKey];
236
+ const gcSnapshotTree: ISnapshotTree | undefined = baseSnapshot.trees[gcTreeKey];
236
237
  if (gcSnapshotTree === undefined) {
237
238
  // back-compat - Older documents get their gc data reset for simplicity as there are few of them
238
239
  // incremental gc summary will not work with older gc data as well
@@ -845,6 +846,8 @@ export class GarbageCollector implements IGarbageCollector {
845
846
  if (gcDataSuperSet.gcNodes[sourceNodeId] === undefined) {
846
847
  gcDataSuperSet.gcNodes[sourceNodeId] = outboundRoutes;
847
848
  } else {
849
+ // TODO: Fix this violation and remove the disable
850
+ // eslint-disable-next-line @fluid-internal/fluid/no-unchecked-record-access
848
851
  gcDataSuperSet.gcNodes[sourceNodeId].push(...outboundRoutes);
849
852
  }
850
853
  newOutboundRoutesSinceLastRun.push(...outboundRoutes);
@@ -178,7 +178,7 @@ export function computeTombstoneTimeout(
178
178
  sessionExpiryTimeoutMs: number | undefined,
179
179
  ): number | undefined {
180
180
  const bufferMs = oneDayMs;
181
- return (
182
- sessionExpiryTimeoutMs && sessionExpiryTimeoutMs + maxSnapshotCacheExpiryMs + bufferMs
183
- );
181
+ return sessionExpiryTimeoutMs === undefined
182
+ ? undefined
183
+ : sessionExpiryTimeoutMs + maxSnapshotCacheExpiryMs + bufferMs;
184
184
  }
@@ -31,7 +31,7 @@ export function runGarbageCollection(
31
31
 
32
32
  // Get the node for the referenced id and add its outbound routes to referencedIds since they are
33
33
  // also referenced.
34
- const routes = referenceGraph[id];
34
+ const routes: string[] | undefined = referenceGraph[id];
35
35
  if (routes !== undefined) {
36
36
  referencedIds.push(...routes);
37
37
  }
@@ -210,10 +210,9 @@ export class GCTelemetryTracker {
210
210
  return this.configs.tombstoneTimeoutMs;
211
211
  }
212
212
  case UnreferencedState.SweepReady: {
213
- return (
214
- this.configs.tombstoneTimeoutMs &&
215
- this.configs.tombstoneTimeoutMs + this.configs.sweepGracePeriodMs
216
- );
213
+ return this.configs.tombstoneTimeoutMs === undefined
214
+ ? undefined
215
+ : this.configs.tombstoneTimeoutMs + this.configs.sweepGracePeriodMs;
217
216
  }
218
217
  default: {
219
218
  return undefined;
@@ -327,7 +326,7 @@ export class GCTelemetryTracker {
327
326
  if (
328
327
  usageType === "Loaded" &&
329
328
  this.configs.throwOnTombstoneLoad &&
330
- !headers?.allowTombstone
329
+ headers?.allowTombstone !== true
331
330
  ) {
332
331
  this.mc.logger.sendErrorEvent(event);
333
332
  } else {
@@ -190,7 +190,7 @@ export class InboundBatchAggregator {
190
190
  // - here, when queue was empty and start of batch showed up (batchMetadata === true below).
191
191
  // 2. resumed when batch end comes in (batchMetadata === false below)
192
192
 
193
- if (batchMetadata) {
193
+ if (batchMetadata === true) {
194
194
  assert(
195
195
  this.currentBatchClientId === undefined,
196
196
  0x29e /* "there can't be active batch" */,
package/src/metadata.ts CHANGED
@@ -52,7 +52,8 @@ export interface IBlobMetadata {
52
52
 
53
53
  export const isBlobMetadata = (metadata: unknown): metadata is IBlobMetadata => {
54
54
  return (
55
- !!metadata &&
55
+ typeof metadata === "object" &&
56
+ metadata !== null &&
56
57
  typeof (metadata as IBlobMetadata).blobId === "string" &&
57
58
  typeof (metadata as IBlobMetadata).localId === "string"
58
59
  );
@@ -134,9 +134,9 @@ export class OpGroupingManager {
134
134
  // We expect this will be on the first message, if present at all.
135
135
  let groupedBatchId;
136
136
  for (const message of batch.messages) {
137
- if (message.metadata) {
137
+ if (message.metadata !== undefined) {
138
138
  const { batch: _batch, batchId, ...rest } = message.metadata;
139
- if (batchId) {
139
+ if (batchId !== undefined) {
140
140
  groupedBatchId = batchId;
141
141
  }
142
142
  assert(Object.keys(rest).length === 0, 0x5dd /* cannot group ops with metadata */);
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.61.0";
9
+ export const pkgVersion = "2.62.0";