@fluidframework/container-runtime 2.30.0 → 2.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +588 -584
  2. package/dist/channelCollection.js +1 -1
  3. package/dist/channelCollection.js.map +1 -1
  4. package/dist/containerRuntime.d.ts +19 -4
  5. package/dist/containerRuntime.d.ts.map +1 -1
  6. package/dist/containerRuntime.js +100 -74
  7. package/dist/containerRuntime.js.map +1 -1
  8. package/dist/dataStoreContext.d.ts +6 -1
  9. package/dist/dataStoreContext.d.ts.map +1 -1
  10. package/dist/dataStoreContext.js +12 -1
  11. package/dist/dataStoreContext.js.map +1 -1
  12. package/dist/gc/gcTelemetry.js +2 -2
  13. package/dist/gc/gcTelemetry.js.map +1 -1
  14. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  15. package/dist/opLifecycle/batchManager.js +16 -5
  16. package/dist/opLifecycle/batchManager.js.map +1 -1
  17. package/dist/opLifecycle/outbox.d.ts +12 -3
  18. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  19. package/dist/opLifecycle/outbox.js +41 -21
  20. package/dist/opLifecycle/outbox.js.map +1 -1
  21. package/dist/packageVersion.d.ts +1 -1
  22. package/dist/packageVersion.js +1 -1
  23. package/dist/packageVersion.js.map +1 -1
  24. package/dist/pendingStateManager.d.ts +1 -0
  25. package/dist/pendingStateManager.d.ts.map +1 -1
  26. package/dist/pendingStateManager.js +12 -2
  27. package/dist/pendingStateManager.js.map +1 -1
  28. package/dist/runCounter.d.ts +11 -0
  29. package/dist/runCounter.d.ts.map +1 -0
  30. package/dist/runCounter.js +43 -0
  31. package/dist/runCounter.js.map +1 -0
  32. package/dist/runtimeLayerCompatState.d.ts +51 -0
  33. package/dist/runtimeLayerCompatState.d.ts.map +1 -0
  34. package/dist/runtimeLayerCompatState.js +123 -0
  35. package/dist/runtimeLayerCompatState.js.map +1 -0
  36. package/dist/summary/summarizerNode/summarizerNode.d.ts +2 -2
  37. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  38. package/dist/summary/summarizerNode/summarizerNode.js +4 -4
  39. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  40. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -18
  41. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  42. package/dist/summary/summarizerNode/summarizerNodeUtils.js +0 -27
  43. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  44. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  45. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  46. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +1 -2
  47. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  48. package/lib/channelCollection.js +1 -1
  49. package/lib/channelCollection.js.map +1 -1
  50. package/lib/containerRuntime.d.ts +19 -4
  51. package/lib/containerRuntime.d.ts.map +1 -1
  52. package/lib/containerRuntime.js +100 -74
  53. package/lib/containerRuntime.js.map +1 -1
  54. package/lib/dataStoreContext.d.ts +6 -1
  55. package/lib/dataStoreContext.d.ts.map +1 -1
  56. package/lib/dataStoreContext.js +12 -1
  57. package/lib/dataStoreContext.js.map +1 -1
  58. package/lib/gc/gcTelemetry.js +2 -2
  59. package/lib/gc/gcTelemetry.js.map +1 -1
  60. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  61. package/lib/opLifecycle/batchManager.js +16 -5
  62. package/lib/opLifecycle/batchManager.js.map +1 -1
  63. package/lib/opLifecycle/outbox.d.ts +12 -3
  64. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  65. package/lib/opLifecycle/outbox.js +43 -23
  66. package/lib/opLifecycle/outbox.js.map +1 -1
  67. package/lib/packageVersion.d.ts +1 -1
  68. package/lib/packageVersion.js +1 -1
  69. package/lib/packageVersion.js.map +1 -1
  70. package/lib/pendingStateManager.d.ts +1 -0
  71. package/lib/pendingStateManager.d.ts.map +1 -1
  72. package/lib/pendingStateManager.js +12 -2
  73. package/lib/pendingStateManager.js.map +1 -1
  74. package/lib/runCounter.d.ts +11 -0
  75. package/lib/runCounter.d.ts.map +1 -0
  76. package/lib/runCounter.js +39 -0
  77. package/lib/runCounter.js.map +1 -0
  78. package/lib/runtimeLayerCompatState.d.ts +51 -0
  79. package/lib/runtimeLayerCompatState.d.ts.map +1 -0
  80. package/lib/runtimeLayerCompatState.js +118 -0
  81. package/lib/runtimeLayerCompatState.js.map +1 -0
  82. package/lib/summary/summarizerNode/summarizerNode.d.ts +2 -2
  83. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  84. package/lib/summary/summarizerNode/summarizerNode.js +5 -5
  85. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  86. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -18
  87. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  88. package/lib/summary/summarizerNode/summarizerNodeUtils.js +1 -25
  89. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  90. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  91. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  92. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +1 -2
  93. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  94. package/lib/tsdoc-metadata.json +1 -1
  95. package/package.json +20 -30
  96. package/src/channelCollection.ts +1 -1
  97. package/src/containerRuntime.ts +148 -100
  98. package/src/dataStoreContext.ts +22 -1
  99. package/src/gc/{garbageCollection.md → README.md} +17 -19
  100. package/src/gc/gcTelemetry.ts +2 -2
  101. package/src/opLifecycle/batchManager.ts +20 -6
  102. package/src/opLifecycle/outbox.ts +64 -24
  103. package/src/packageVersion.ts +1 -1
  104. package/src/pendingStateManager.ts +18 -2
  105. package/src/runCounter.ts +25 -0
  106. package/src/runtimeLayerCompatState.ts +143 -0
  107. package/src/summary/summarizerNode/summarizerNode.ts +6 -5
  108. package/src/summary/summarizerNode/summarizerNodeUtils.ts +1 -27
  109. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +2 -3
  110. package/tsconfig.json +1 -0
  111. package/dist/layerCompatState.d.ts +0 -19
  112. package/dist/layerCompatState.d.ts.map +0 -1
  113. package/dist/layerCompatState.js +0 -64
  114. package/dist/layerCompatState.js.map +0 -1
  115. package/lib/layerCompatState.d.ts +0 -19
  116. package/lib/layerCompatState.d.ts.map +0 -1
  117. package/lib/layerCompatState.js +0 -60
  118. package/lib/layerCompatState.js.map +0 -1
  119. package/prettier.config.cjs +0 -8
  120. package/src/layerCompatState.ts +0 -75
@@ -6,8 +6,9 @@
6
6
  import { ICriticalContainerError } from "@fluidframework/container-definitions";
7
7
  import { IBatchMessage } from "@fluidframework/container-definitions/internal";
8
8
  import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
9
- import { assert } from "@fluidframework/core-utils/internal";
9
+ import { assert, Lazy } from "@fluidframework/core-utils/internal";
10
10
  import {
11
+ DataProcessingError,
11
12
  GenericError,
12
13
  UsageError,
13
14
  createChildLogger,
@@ -34,9 +35,16 @@ import { ensureContentsDeserialized } from "./remoteMessageProcessor.js";
34
35
 
35
36
  export interface IOutboxConfig {
36
37
  readonly compressionOptions: ICompressionRuntimeOptions;
37
- // The maximum size of a batch that we can send over the wire.
38
+ /**
39
+ * The maximum size of a batch that we can send over the wire.
40
+ */
38
41
  readonly maxBatchSizeInBytes: number;
39
- readonly disablePartialFlush: boolean;
42
+ /**
43
+ * If true, maybeFlushPartialBatch will flush the batch if the reference sequence number changed
44
+ * since the batch started. Otherwise, it will throw in this case (apart from reentrancy which is handled elsewhere).
45
+ * Once the new throw-based flow is proved in a production environment, this option will be removed.
46
+ */
47
+ readonly flushPartialBatches: boolean;
40
48
  }
41
49
 
42
50
  export interface IOutboxParameters {
@@ -170,8 +178,9 @@ export class Outbox {
170
178
 
171
179
  /**
172
180
  * Detect whether batching has been interrupted by an incoming message being processed. In this case,
173
- * we will flush the accumulated messages to account for that and create a new batch with the new
174
- * message as the first message.
181
+ * we will flush the accumulated messages to account for that (if allowed) and create a new batch with the new
182
+ * message as the first message. If flushing partial batch is not enabled, we will throw (except for reentrant ops).
183
+ * This would indicate we expected this case to be precluded by logic elsewhere.
175
184
  *
176
185
  * @remarks - To detect batch interruption, we compare both the reference sequence number
177
186
  * (i.e. last message processed by DeltaManager) and the client sequence number of the
@@ -183,9 +192,8 @@ export class Outbox {
183
192
  const blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;
184
193
  const idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;
185
194
  assert(
186
- this.params.config.disablePartialFlush ||
187
- (sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&
188
- sequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums)),
195
+ sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&
196
+ sequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums),
189
197
  0x58d /* Reference sequence numbers from both batches must be in sync */,
190
198
  );
191
199
 
@@ -200,25 +208,54 @@ export class Outbox {
200
208
  return;
201
209
  }
202
210
 
211
+ // Reference and/or Client sequence number will be advancing while processing this batch,
212
+ // so we can't use this check to detect wrongdoing. But we will still log via telemetry.
213
+ // This is rare, and the reentrancy will be handled during Flush.
214
+ const expectedDueToReentrancy = this.isContextReentrant();
215
+
216
+ const errorWrapper = new Lazy(() =>
217
+ getLongStack(() =>
218
+ DataProcessingError.create(
219
+ "Sequence numbers advanced as if ops were processed while a batch is accumulating",
220
+ "outboxSequenceNumberCoherencyCheck",
221
+ ),
222
+ ),
223
+ );
203
224
  if (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {
204
225
  this.logger.sendTelemetryEvent(
205
226
  {
206
- category: this.params.config.disablePartialFlush ? "error" : "generic",
227
+ // Only log error if this is truly unexpected
228
+ category:
229
+ expectedDueToReentrancy || this.params.config.flushPartialBatches
230
+ ? "generic"
231
+ : "error",
207
232
  eventName: "ReferenceSequenceNumberMismatch",
208
- mainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,
209
- mainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,
210
- blobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,
211
- blobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,
212
- currentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,
213
- currentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,
233
+ Data_details: {
234
+ expectedDueToReentrancy,
235
+ mainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,
236
+ mainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,
237
+ blobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,
238
+ blobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,
239
+ currentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,
240
+ currentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,
241
+ },
214
242
  },
215
- getLongStack(() => new UsageError("Submission of an out of order message")),
243
+ errorWrapper.value,
216
244
  );
217
245
  }
218
246
 
219
- if (!this.params.config.disablePartialFlush) {
247
+ // If we're configured to flush partial batches, do that now and return (don't throw)
248
+ if (this.params.config.flushPartialBatches) {
220
249
  this.flushAll();
250
+ return;
221
251
  }
252
+
253
+ // If we are in a reentrant context, we know this can happen without causing any harm.
254
+ if (expectedDueToReentrancy) {
255
+ return;
256
+ }
257
+
258
+ throw errorWrapper.value;
222
259
  }
223
260
 
224
261
  public submit(message: BatchMessage): void {
@@ -273,17 +310,20 @@ export class Outbox {
273
310
  }
274
311
 
275
312
  private flushAll(resubmittingBatchId?: BatchId): void {
276
- // If we're resubmitting and all batches are empty, we need to flush an empty batch.
277
- // Note that we currently resubmit one batch at a time, so on resubmit, 2 of the 3 batches will *always* be empty.
278
- // It's theoretically possible that we don't *need* to resubmit this empty batch, and in those cases, it'll safely be ignored
279
- // by the rest of the system, including remote clients.
280
- // In some cases we *must* resubmit the empty batch (to match up with a non-empty version tracked locally by a container fork), so we do it always.
281
313
  const allBatchesEmpty =
282
314
  this.idAllocationBatch.empty && this.blobAttachBatch.empty && this.mainBatch.empty;
283
- if (resubmittingBatchId && allBatchesEmpty) {
284
- this.flushEmptyBatch(resubmittingBatchId);
315
+ if (allBatchesEmpty) {
316
+ // If we're resubmitting and all batches are empty, we need to flush an empty batch.
317
+ // Note that we currently resubmit one batch at a time, so on resubmit, 2 of the 3 batches will *always* be empty.
318
+ // It's theoretically possible that we don't *need* to resubmit this empty batch, and in those cases, it'll safely be ignored
319
+ // by the rest of the system, including remote clients.
320
+ // In some cases we *must* resubmit the empty batch (to match up with a non-empty version tracked locally by a container fork), so we do it always.
321
+ if (resubmittingBatchId) {
322
+ this.flushEmptyBatch(resubmittingBatchId);
323
+ }
285
324
  return;
286
325
  }
326
+
287
327
  // Don't use resubmittingBatchId for idAllocationBatch.
288
328
  // ID Allocation messages are not directly resubmitted so we don't want to reuse the batch ID.
289
329
  this.flushInternal(this.idAllocationBatch);
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.30.0";
9
+ export const pkgVersion = "2.31.1";
@@ -134,7 +134,7 @@ function scrubAndStringify(
134
134
  // Scrub the whole object in case there are unexpected keys
135
135
  const scrubbed: Record<string, unknown> = typesOfKeys(message);
136
136
 
137
- // For these known/expected keys, we can either drill in (for contents)
137
+ // For these known/expected keys, we can either drill into the object (for contents)
138
138
  // or just use the value as-is (since it's not personal info)
139
139
  scrubbed.contents = message.contents && typesOfKeys(message.contents);
140
140
  scrubbed.type = message.type;
@@ -145,7 +145,7 @@ function scrubAndStringify(
145
145
  /**
146
146
  * Finds and returns the index where the strings diverge, and the character at that index in each string (or undefined if not applicable)
147
147
  */
148
- export function findFirstCharacterMismatched(
148
+ function findFirstRawCharacterMismatched(
149
149
  a: string,
150
150
  b: string,
151
151
  ): [index: number, charA?: string, charB?: string] {
@@ -164,6 +164,22 @@ export function findFirstCharacterMismatched(
164
164
  : [minLength, a[minLength], b[minLength]];
165
165
  }
166
166
 
167
+ /**
168
+ * Finds and returns the index where the strings diverge, and the character at that index in each string (or undefined if not applicable)
169
+ * It scrubs non-ASCII characters since they convey more meaning (privacy consideration)
170
+ */
171
+ export function findFirstCharacterMismatched(
172
+ a: string,
173
+ b: string,
174
+ ): [index: number, charA?: string, charB?: string] {
175
+ const [index, rawCharA, rawCharB] = findFirstRawCharacterMismatched(a, b);
176
+
177
+ const charA = (rawCharA?.codePointAt(0) ?? 0) <= 0x7f ? rawCharA : "[non-ASCII]";
178
+ const charB = (rawCharB?.codePointAt(0) ?? 0) <= 0x7f ? rawCharB : "[non-ASCII]";
179
+
180
+ return [index, charA, charB];
181
+ }
182
+
167
183
  function withoutLocalOpMetadata(message: IPendingMessage): IPendingMessage {
168
184
  return {
169
185
  ...message,
@@ -0,0 +1,25 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ export class RunCounter {
7
+ #runs = 0;
8
+
9
+ public get running(): boolean {
10
+ return this.#runs !== 0;
11
+ }
12
+
13
+ public get runs(): number {
14
+ return this.#runs;
15
+ }
16
+
17
+ public run<T>(act: () => T): T {
18
+ this.#runs++;
19
+ try {
20
+ return act();
21
+ } finally {
22
+ this.#runs--;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,143 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import {
7
+ checkLayerCompatibility,
8
+ type ILayerCompatDetails,
9
+ type ILayerCompatSupportRequirements,
10
+ } from "@fluid-internal/client-utils";
11
+ import type { ICriticalContainerError } from "@fluidframework/container-definitions";
12
+ import { UsageError } from "@fluidframework/telemetry-utils/internal";
13
+
14
+ import { pkgVersion } from "./packageVersion.js";
15
+
16
+ /**
17
+ * The core compatibility details of the Runtime layer that is the same across all layer boundaries.
18
+ * @internal
19
+ */
20
+ export const runtimeCoreCompatDetails = {
21
+ /**
22
+ * The package version of the Runtime layer.
23
+ */
24
+ pkgVersion,
25
+ /**
26
+ * The current generation of the Runtime layer.
27
+ */
28
+ generation: 1,
29
+ };
30
+
31
+ /**
32
+ * Runtime's compatibility details that is exposed to the Loader layer.
33
+ * @internal
34
+ */
35
+ export const runtimeCompatDetailsForLoader: ILayerCompatDetails = {
36
+ ...runtimeCoreCompatDetails,
37
+ /**
38
+ * The features supported by the Runtime layer across the Runtime / Loader boundary.
39
+ */
40
+ supportedFeatures: new Set<string>(),
41
+ };
42
+
43
+ /**
44
+ * The requirements that the Loader layer must meet to be compatible with this Runtime.
45
+ * @internal
46
+ */
47
+ export const loaderSupportRequirements: ILayerCompatSupportRequirements = {
48
+ /**
49
+ * Minimum generation that Loader must be at to be compatible with Runtime. Note that 0 is used here so
50
+ * that Loader layers before the introduction of the layer compatibility enforcement are compatible.
51
+ */
52
+ minSupportedGeneration: 0,
53
+ /**
54
+ * The features that the Loader must support to be compatible with Runtime.
55
+ */
56
+ requiredFeatures: [],
57
+ };
58
+
59
+ /**
60
+ * Runtime's compatibility details that is exposed to the DataStore layer.
61
+ * @internal
62
+ */
63
+ export const runtimeCompatDetailsForDataStore: ILayerCompatDetails = {
64
+ ...runtimeCoreCompatDetails,
65
+ /**
66
+ * The features supported by the Runtime layer across the Runtime / Loader boundary.
67
+ */
68
+ supportedFeatures: new Set<string>(),
69
+ };
70
+
71
+ /**
72
+ * The requirements that the DataStore layer must meet to be compatible with this Runtime.
73
+ * @internal
74
+ */
75
+ export const dataStoreSupportRequirements: ILayerCompatSupportRequirements = {
76
+ /**
77
+ * Minimum generation that DataStore must be at to be compatible with Runtime. Note that 0 is used here so
78
+ * that DataStore layers before the introduction of the layer compatibility enforcement are compatible.
79
+ */
80
+ minSupportedGeneration: 0,
81
+ /**
82
+ * The features that the DataStore must support to be compatible with Runtime.
83
+ */
84
+ requiredFeatures: [],
85
+ };
86
+
87
+ /**
88
+ * Validates that the Loader layer is compatible with this Runtime.
89
+ * @internal
90
+ */
91
+ export function validateLoaderCompatibility(
92
+ maybeloaderCompatDetailsForRuntime: ILayerCompatDetails | undefined,
93
+ disposeFn: (error?: ICriticalContainerError) => void,
94
+ ): void {
95
+ const layerCheckResult = checkLayerCompatibility(
96
+ loaderSupportRequirements,
97
+ maybeloaderCompatDetailsForRuntime,
98
+ );
99
+ if (!layerCheckResult.isCompatible) {
100
+ const error = new UsageError("Runtime is not compatible with Loader", {
101
+ errorDetails: JSON.stringify({
102
+ runtimeVersion: runtimeCoreCompatDetails.pkgVersion,
103
+ loaderVersion: maybeloaderCompatDetailsForRuntime?.pkgVersion,
104
+ runtimeGeneration: runtimeCoreCompatDetails.generation,
105
+ loaderGeneration: maybeloaderCompatDetailsForRuntime?.generation,
106
+ minSupportedGeneration: loaderSupportRequirements.minSupportedGeneration,
107
+ isGenerationCompatible: layerCheckResult.isGenerationCompatible,
108
+ unsupportedFeatures: layerCheckResult.unsupportedFeatures,
109
+ }),
110
+ });
111
+ disposeFn(error);
112
+ throw error;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Validates that the DataStore layer is compatible with this Runtime.
118
+ * @internal
119
+ */
120
+ export function validateDatastoreCompatibility(
121
+ maybeDataStoreCompatDetails: ILayerCompatDetails | undefined,
122
+ disposeFn: () => void,
123
+ ): void {
124
+ const layerCheckResult = checkLayerCompatibility(
125
+ dataStoreSupportRequirements,
126
+ maybeDataStoreCompatDetails,
127
+ );
128
+ if (!layerCheckResult.isCompatible) {
129
+ const error = new UsageError("Runtime is not compatible with DataStore", {
130
+ errorDetails: JSON.stringify({
131
+ runtimeVersion: runtimeCoreCompatDetails.pkgVersion,
132
+ dataStoreVersion: maybeDataStoreCompatDetails?.pkgVersion,
133
+ runtimeGeneration: runtimeCoreCompatDetails.generation,
134
+ dataStoreGeneration: maybeDataStoreCompatDetails?.generation,
135
+ minSupportedGeneration: dataStoreSupportRequirements.minSupportedGeneration,
136
+ isGenerationCompatible: layerCheckResult.isGenerationCompatible,
137
+ unsupportedFeatures: layerCheckResult.unsupportedFeatures,
138
+ }),
139
+ });
140
+ disposeFn();
141
+ throw error;
142
+ }
143
+ }
@@ -11,6 +11,7 @@ import {
11
11
  ISequencedDocumentMessage,
12
12
  } from "@fluidframework/driver-definitions/internal";
13
13
  import {
14
+ channelsTreeName,
14
15
  IExperimentalIncrementalSummaryContext,
15
16
  ITelemetryContext,
16
17
  CreateChildSummarizerNodeParam,
@@ -32,7 +33,6 @@ import {
32
33
  } from "@fluidframework/telemetry-utils/internal";
33
34
 
34
35
  import {
35
- EscapedPath,
36
36
  ICreateChildDetails,
37
37
  IRefreshSummaryResult,
38
38
  IStartSummaryResult,
@@ -70,7 +70,7 @@ export class SummarizerNode implements IRootSummarizerNode {
70
70
  * (this getter is primarily only used in the test code)
71
71
  */
72
72
  public get summaryHandleId(): string {
73
- return this._summaryHandleId.toString();
73
+ return this._summaryHandleId;
74
74
  }
75
75
 
76
76
  protected readonly children = new Map<string, SummarizerNode>();
@@ -101,7 +101,7 @@ export class SummarizerNode implements IRootSummarizerNode {
101
101
  /**
102
102
  * Encoded handle or path to the node
103
103
  */
104
- private readonly _summaryHandleId: EscapedPath,
104
+ private readonly _summaryHandleId: string,
105
105
  private _changeSequenceNumber: number,
106
106
  /**
107
107
  * Summary reference sequence number, i.e. last sequence number seen when last successful summary was created
@@ -591,7 +591,8 @@ export class SummarizerNode implements IRootSummarizerNode {
591
591
  }
592
592
 
593
593
  const childTelemetryNodeId = `${this.telemetryNodeId ?? ""}/${id}`;
594
- const childSummaryHandleId = this._summaryHandleId.createChildPath(EscapedPath.create(id));
594
+ // parentHandleId/.channels/childId
595
+ const childSummaryHandleId = `${this._summaryHandleId}/${channelsTreeName}/${id}`;
595
596
 
596
597
  return {
597
598
  changeSequenceNumber,
@@ -671,7 +672,7 @@ export const createRootSummarizerNode = (
671
672
  logger,
672
673
  summarizeInternalFn,
673
674
  config,
674
- EscapedPath.create("") /* summaryHandleId */,
675
+ "" /* summaryHandleId */,
675
676
  changeSequenceNumber,
676
677
  referenceSequenceNumber,
677
678
  undefined /* wipSummaryLogger */,
@@ -5,7 +5,6 @@
5
5
 
6
6
  import { SummaryObject } from "@fluidframework/driver-definitions";
7
7
  import { ISnapshotTree } from "@fluidframework/driver-definitions/internal";
8
- import { channelsTreeName } from "@fluidframework/runtime-definitions/internal";
9
8
  import {
10
9
  ITelemetryLoggerExt,
11
10
  TelemetryDataTag,
@@ -80,31 +79,6 @@ export interface ISummarizerNodeRootContract {
80
79
  ): Promise<IRefreshSummaryResult>;
81
80
  }
82
81
 
83
- /**
84
- * Class to build paths for nodes in a tree with escaped special characters
85
- */
86
- export class EscapedPath {
87
- private constructor(public readonly path: string) {}
88
-
89
- /**
90
- * Creates and returns a new instance of this class.
91
- * @param path - Id or path part of a node
92
- */
93
- public static create(path: string): EscapedPath {
94
- return new EscapedPath(encodeURIComponent(path));
95
- }
96
- public toString(): string {
97
- return this.path;
98
- }
99
- /**
100
- * Creates and returns a new instance of this class for child of the current node.
101
- */
102
- public createChildPath(childNodePath: EscapedPath): EscapedPath {
103
- return new EscapedPath(
104
- `${this.path}/${encodeURIComponent(channelsTreeName)}/${childNodePath.path}`,
105
- );
106
- }
107
- }
108
82
  export interface PendingSummaryInfo {
109
83
  /**
110
84
  * The sequence number at which the summary was created.
@@ -127,7 +101,7 @@ export interface ICreateChildDetails {
127
101
  /**
128
102
  * Summary handle for child node
129
103
  */
130
- summaryHandleId: EscapedPath;
104
+ summaryHandleId: string;
131
105
  /**
132
106
  * the reference sequence number of the last successful summary.
133
107
  */
@@ -24,7 +24,6 @@ import { cloneGCData, unpackChildNodesGCDetails } from "../../gc/index.js";
24
24
 
25
25
  import { SummarizerNode } from "./summarizerNode.js";
26
26
  import {
27
- EscapedPath,
28
27
  ICreateChildDetails,
29
28
  IStartSummaryResult,
30
29
  ISummarizerNodeRootContract,
@@ -93,7 +92,7 @@ export class SummarizerNodeWithGC extends SummarizerNode implements IRootSummari
93
92
  logger: ITelemetryBaseLogger,
94
93
  summarizeInternalFn: SummarizeInternalFn,
95
94
  config: ISummarizerNodeConfigWithGC,
96
- _summaryHandleId: EscapedPath,
95
+ _summaryHandleId: string,
97
96
  changeSequenceNumber: number,
98
97
  /**
99
98
  * Summary reference sequence number, i.e. last sequence number seen when it was created
@@ -525,7 +524,7 @@ export const createRootSummarizerNodeWithGC = (
525
524
  logger,
526
525
  summarizeInternalFn,
527
526
  config,
528
- EscapedPath.create("") /* summaryHandleId */,
527
+ "" /* summaryHandleId */,
529
528
  changeSequenceNumber,
530
529
  referenceSequenceNumber,
531
530
  undefined /* wipSummaryLogger */,
package/tsconfig.json CHANGED
@@ -5,6 +5,7 @@
5
5
  "compilerOptions": {
6
6
  "rootDir": "./src",
7
7
  "outDir": "./lib",
8
+ // TODO: AB#34168 Enable noUncheckedIndexedAccess for packages/runtime/container-runtime
8
9
  "noUncheckedIndexedAccess": false,
9
10
  "exactOptionalPropertyTypes": false,
10
11
  },
@@ -1,19 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { type ILayerCompatDetails, type ILayerCompatSupportRequirements } from "@fluid-internal/client-utils";
6
- import type { ICriticalContainerError } from "@fluidframework/container-definitions";
7
- /**
8
- * Runtime's compatibility details that is exposed to the Loader layer.
9
- */
10
- export declare const RuntimeCompatDetails: ILayerCompatDetails;
11
- /**
12
- * The requirements that the Loader layer must meet to be compatible with this Runtime.
13
- */
14
- export declare const LoaderSupportRequirements: ILayerCompatSupportRequirements;
15
- /**
16
- * Validates that the Loader layer is compatible with this Runtime.
17
- */
18
- export declare function validateLoaderCompatibility(maybeLoaderCompatDetails: ILayerCompatDetails | undefined, disposeFn: (error?: ICriticalContainerError) => void): void;
19
- //# sourceMappingURL=layerCompatState.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"layerCompatState.d.ts","sourceRoot":"","sources":["../src/layerCompatState.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,+BAA+B,EACpC,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAKrF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAalC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,+BAUvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,2BAA2B,CAC1C,wBAAwB,EAAE,mBAAmB,GAAG,SAAS,EACzD,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,uBAAuB,KAAK,IAAI,GAClD,IAAI,CAoBN"}
@@ -1,64 +0,0 @@
1
- "use strict";
2
- /*!
3
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
- * Licensed under the MIT License.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.validateLoaderCompatibility = exports.LoaderSupportRequirements = exports.RuntimeCompatDetails = void 0;
8
- const client_utils_1 = require("@fluid-internal/client-utils");
9
- const internal_1 = require("@fluidframework/telemetry-utils/internal");
10
- const packageVersion_js_1 = require("./packageVersion.js");
11
- /**
12
- * Runtime's compatibility details that is exposed to the Loader layer.
13
- */
14
- exports.RuntimeCompatDetails = {
15
- /**
16
- * The package version of the Runtime layer.
17
- */
18
- pkgVersion: packageVersion_js_1.pkgVersion,
19
- /**
20
- * The current generation of the Runtime layer.
21
- */
22
- generation: 1,
23
- /**
24
- * The features supported by the Runtime layer across the Runtime / Loader boundary.
25
- */
26
- supportedFeatures: new Set(),
27
- };
28
- /**
29
- * The requirements that the Loader layer must meet to be compatible with this Runtime.
30
- */
31
- exports.LoaderSupportRequirements = {
32
- /**
33
- * Minimum generation that Loader must be at to be compatible with Runtime.
34
- */
35
- minSupportedGeneration: 0,
36
- /**
37
- * The features that the Loader must support to be compatible with Runtime. Note that 0 is used here for
38
- * Loader layers before the introduction of the layer compatibility enforcement.
39
- */
40
- requiredFeatures: [],
41
- };
42
- /**
43
- * Validates that the Loader layer is compatible with this Runtime.
44
- */
45
- function validateLoaderCompatibility(maybeLoaderCompatDetails, disposeFn) {
46
- const layerCheckResult = (0, client_utils_1.checkLayerCompatibility)(exports.LoaderSupportRequirements, maybeLoaderCompatDetails);
47
- if (!layerCheckResult.isCompatible) {
48
- const error = new internal_1.UsageError("Runtime is not compatible with Loader", {
49
- errorDetails: JSON.stringify({
50
- runtimeVersion: exports.RuntimeCompatDetails.pkgVersion,
51
- loaderVersion: maybeLoaderCompatDetails?.pkgVersion,
52
- runtimeGeneration: exports.RuntimeCompatDetails.generation,
53
- loaderGeneration: maybeLoaderCompatDetails?.generation,
54
- minSupportedGeneration: exports.LoaderSupportRequirements.minSupportedGeneration,
55
- isGenerationCompatible: layerCheckResult.isGenerationCompatible,
56
- unsupportedFeatures: layerCheckResult.unsupportedFeatures,
57
- }),
58
- });
59
- disposeFn(error);
60
- throw error;
61
- }
62
- }
63
- exports.validateLoaderCompatibility = validateLoaderCompatibility;
64
- //# sourceMappingURL=layerCompatState.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"layerCompatState.js","sourceRoot":"","sources":["../src/layerCompatState.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAIsC;AAEtC,uEAAsE;AAEtE,2DAAiD;AAEjD;;GAEG;AACU,QAAA,oBAAoB,GAAwB;IACxD;;OAEG;IACH,UAAU,EAAV,8BAAU;IACV;;OAEG;IACH,UAAU,EAAE,CAAC;IACb;;OAEG;IACH,iBAAiB,EAAE,IAAI,GAAG,EAAU;CACpC,CAAC;AAEF;;GAEG;AACU,QAAA,yBAAyB,GAAoC;IACzE;;OAEG;IACH,sBAAsB,EAAE,CAAC;IACzB;;;OAGG;IACH,gBAAgB,EAAE,EAAE;CACpB,CAAC;AAEF;;GAEG;AACH,SAAgB,2BAA2B,CAC1C,wBAAyD,EACzD,SAAoD;IAEpD,MAAM,gBAAgB,GAAG,IAAA,sCAAuB,EAC/C,iCAAyB,EACzB,wBAAwB,CACxB,CAAC;IACF,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,qBAAU,CAAC,uCAAuC,EAAE;YACrE,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC;gBAC5B,cAAc,EAAE,4BAAoB,CAAC,UAAU;gBAC/C,aAAa,EAAE,wBAAwB,EAAE,UAAU;gBACnD,iBAAiB,EAAE,4BAAoB,CAAC,UAAU;gBAClD,gBAAgB,EAAE,wBAAwB,EAAE,UAAU;gBACtD,sBAAsB,EAAE,iCAAyB,CAAC,sBAAsB;gBACxE,sBAAsB,EAAE,gBAAgB,CAAC,sBAAsB;gBAC/D,mBAAmB,EAAE,gBAAgB,CAAC,mBAAmB;aACzD,CAAC;SACF,CAAC,CAAC;QACH,SAAS,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,KAAK,CAAC;IACb,CAAC;AACF,CAAC;AAvBD,kEAuBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tcheckLayerCompatibility,\n\ttype ILayerCompatDetails,\n\ttype ILayerCompatSupportRequirements,\n} from \"@fluid-internal/client-utils\";\nimport type { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { pkgVersion } from \"./packageVersion.js\";\n\n/**\n * Runtime's compatibility details that is exposed to the Loader layer.\n */\nexport const RuntimeCompatDetails: ILayerCompatDetails = {\n\t/**\n\t * The package version of the Runtime layer.\n\t */\n\tpkgVersion,\n\t/**\n\t * The current generation of the Runtime layer.\n\t */\n\tgeneration: 1,\n\t/**\n\t * The features supported by the Runtime layer across the Runtime / Loader boundary.\n\t */\n\tsupportedFeatures: new Set<string>(),\n};\n\n/**\n * The requirements that the Loader layer must meet to be compatible with this Runtime.\n */\nexport const LoaderSupportRequirements: ILayerCompatSupportRequirements = {\n\t/**\n\t * Minimum generation that Loader must be at to be compatible with Runtime.\n\t */\n\tminSupportedGeneration: 0,\n\t/**\n\t * The features that the Loader must support to be compatible with Runtime. Note that 0 is used here for\n\t * Loader layers before the introduction of the layer compatibility enforcement.\n\t */\n\trequiredFeatures: [],\n};\n\n/**\n * Validates that the Loader layer is compatible with this Runtime.\n */\nexport function validateLoaderCompatibility(\n\tmaybeLoaderCompatDetails: ILayerCompatDetails | undefined,\n\tdisposeFn: (error?: ICriticalContainerError) => void,\n): void {\n\tconst layerCheckResult = checkLayerCompatibility(\n\t\tLoaderSupportRequirements,\n\t\tmaybeLoaderCompatDetails,\n\t);\n\tif (!layerCheckResult.isCompatible) {\n\t\tconst error = new UsageError(\"Runtime is not compatible with Loader\", {\n\t\t\terrorDetails: JSON.stringify({\n\t\t\t\truntimeVersion: RuntimeCompatDetails.pkgVersion,\n\t\t\t\tloaderVersion: maybeLoaderCompatDetails?.pkgVersion,\n\t\t\t\truntimeGeneration: RuntimeCompatDetails.generation,\n\t\t\t\tloaderGeneration: maybeLoaderCompatDetails?.generation,\n\t\t\t\tminSupportedGeneration: LoaderSupportRequirements.minSupportedGeneration,\n\t\t\t\tisGenerationCompatible: layerCheckResult.isGenerationCompatible,\n\t\t\t\tunsupportedFeatures: layerCheckResult.unsupportedFeatures,\n\t\t\t}),\n\t\t});\n\t\tdisposeFn(error);\n\t\tthrow error;\n\t}\n}\n"]}
@@ -1,19 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { type ILayerCompatDetails, type ILayerCompatSupportRequirements } from "@fluid-internal/client-utils";
6
- import type { ICriticalContainerError } from "@fluidframework/container-definitions";
7
- /**
8
- * Runtime's compatibility details that is exposed to the Loader layer.
9
- */
10
- export declare const RuntimeCompatDetails: ILayerCompatDetails;
11
- /**
12
- * The requirements that the Loader layer must meet to be compatible with this Runtime.
13
- */
14
- export declare const LoaderSupportRequirements: ILayerCompatSupportRequirements;
15
- /**
16
- * Validates that the Loader layer is compatible with this Runtime.
17
- */
18
- export declare function validateLoaderCompatibility(maybeLoaderCompatDetails: ILayerCompatDetails | undefined, disposeFn: (error?: ICriticalContainerError) => void): void;
19
- //# sourceMappingURL=layerCompatState.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"layerCompatState.d.ts","sourceRoot":"","sources":["../src/layerCompatState.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,+BAA+B,EACpC,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAKrF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAalC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,+BAUvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,2BAA2B,CAC1C,wBAAwB,EAAE,mBAAmB,GAAG,SAAS,EACzD,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,uBAAuB,KAAK,IAAI,GAClD,IAAI,CAoBN"}