@fluidframework/container-runtime 2.1.0-281041 → 2.1.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 (61) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +4 -4
  3. package/container-runtime.test-files.tar +0 -0
  4. package/dist/containerRuntime.d.ts +1 -0
  5. package/dist/containerRuntime.d.ts.map +1 -1
  6. package/dist/containerRuntime.js +50 -36
  7. package/dist/containerRuntime.js.map +1 -1
  8. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  9. package/dist/opLifecycle/batchManager.js +1 -1
  10. package/dist/opLifecycle/batchManager.js.map +1 -1
  11. package/dist/opLifecycle/index.d.ts +1 -1
  12. package/dist/opLifecycle/index.d.ts.map +1 -1
  13. package/dist/opLifecycle/index.js +2 -1
  14. package/dist/opLifecycle/index.js.map +1 -1
  15. package/dist/opLifecycle/outbox.js +1 -1
  16. package/dist/opLifecycle/outbox.js.map +1 -1
  17. package/dist/opLifecycle/remoteMessageProcessor.d.ts +9 -7
  18. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  19. package/dist/opLifecycle/remoteMessageProcessor.js +24 -23
  20. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  21. package/dist/packageVersion.d.ts +1 -1
  22. package/dist/packageVersion.d.ts.map +1 -1
  23. package/dist/packageVersion.js +1 -1
  24. package/dist/packageVersion.js.map +1 -1
  25. package/dist/pendingStateManager.d.ts +2 -12
  26. package/dist/pendingStateManager.d.ts.map +1 -1
  27. package/dist/pendingStateManager.js +0 -12
  28. package/dist/pendingStateManager.js.map +1 -1
  29. package/lib/containerRuntime.d.ts +1 -0
  30. package/lib/containerRuntime.d.ts.map +1 -1
  31. package/lib/containerRuntime.js +51 -37
  32. package/lib/containerRuntime.js.map +1 -1
  33. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  34. package/lib/opLifecycle/batchManager.js +1 -1
  35. package/lib/opLifecycle/batchManager.js.map +1 -1
  36. package/lib/opLifecycle/index.d.ts +1 -1
  37. package/lib/opLifecycle/index.d.ts.map +1 -1
  38. package/lib/opLifecycle/index.js +1 -1
  39. package/lib/opLifecycle/index.js.map +1 -1
  40. package/lib/opLifecycle/outbox.js +1 -1
  41. package/lib/opLifecycle/outbox.js.map +1 -1
  42. package/lib/opLifecycle/remoteMessageProcessor.d.ts +9 -7
  43. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  44. package/lib/opLifecycle/remoteMessageProcessor.js +22 -22
  45. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  46. package/lib/packageVersion.d.ts +1 -1
  47. package/lib/packageVersion.d.ts.map +1 -1
  48. package/lib/packageVersion.js +1 -1
  49. package/lib/packageVersion.js.map +1 -1
  50. package/lib/pendingStateManager.d.ts +2 -12
  51. package/lib/pendingStateManager.d.ts.map +1 -1
  52. package/lib/pendingStateManager.js +0 -12
  53. package/lib/pendingStateManager.js.map +1 -1
  54. package/package.json +22 -35
  55. package/src/containerRuntime.ts +62 -41
  56. package/src/opLifecycle/batchManager.ts +4 -1
  57. package/src/opLifecycle/index.ts +5 -1
  58. package/src/opLifecycle/outbox.ts +1 -1
  59. package/src/opLifecycle/remoteMessageProcessor.ts +32 -27
  60. package/src/packageVersion.ts +1 -1
  61. package/src/pendingStateManager.ts +2 -21
@@ -13,6 +13,7 @@ import {
13
13
  ContainerMessageType,
14
14
  type InboundContainerRuntimeMessage,
15
15
  type InboundSequencedContainerRuntimeMessage,
16
+ type InboundSequencedContainerRuntimeMessageOrSystemMessage,
16
17
  type InboundSequencedRecentlyAddedContainerRuntimeMessage,
17
18
  } from "../messageTypes.js";
18
19
  import { asBatchMetadata } from "../metadata.js";
@@ -35,7 +36,6 @@ export class RemoteMessageProcessor {
35
36
  * @remarks For chunked batches, this is the CSN of the "representative" chunk (the final chunk)
36
37
  */
37
38
  private batchStartCsn: number | undefined;
38
- private readonly processorBatch: InboundSequencedContainerRuntimeMessage[] = [];
39
39
 
40
40
  constructor(
41
41
  private readonly opSplitter: OpSplitter,
@@ -52,7 +52,7 @@ export class RemoteMessageProcessor {
52
52
  }
53
53
 
54
54
  /**
55
- * Ungroups and Unchunks the runtime ops of a batch received over the wire
55
+ * Ungroups and Unchunks the runtime ops encapsulated by the single remoteMessage received over the wire
56
56
  * @param remoteMessageCopy - A shallow copy of a message from another client, possibly virtualized
57
57
  * (grouped, compressed, and/or chunked).
58
58
  * Being a shallow copy, it's considered mutable, meaning no other Container or other parallel procedure
@@ -67,19 +67,18 @@ export class RemoteMessageProcessor {
67
67
  * 3. If grouped, ungroup the message
68
68
  * For more details, see https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/container-runtime/src/opLifecycle/README.md#inbound
69
69
  *
70
- * @returns all the unchunked, decompressed, ungrouped, unpacked InboundSequencedContainerRuntimeMessage from a single batch
71
- * or undefined if the batch is not yet complete.
70
+ * @returns the unchunked, decompressed, ungrouped, unpacked SequencedContainerRuntimeMessages encapsulated in the remote message.
71
+ * For ops that weren't virtualized (e.g. System ops that the ContainerRuntime will ultimately ignore),
72
+ * a singleton array [remoteMessageCopy] is returned
72
73
  */
73
74
  public process(remoteMessageCopy: ISequencedDocumentMessage):
74
75
  | {
75
- messages: InboundSequencedContainerRuntimeMessage[];
76
+ messages: InboundSequencedContainerRuntimeMessageOrSystemMessage[];
76
77
  batchStartCsn: number;
77
78
  }
78
79
  | undefined {
79
80
  let message = remoteMessageCopy;
80
81
 
81
- ensureContentsDeserialized(message);
82
-
83
82
  if (isChunkedMessage(message)) {
84
83
  const chunkProcessingResult = this.opSplitter.processChunk(message);
85
84
  // Only continue further if current chunk is the final chunk
@@ -104,10 +103,9 @@ export class RemoteMessageProcessor {
104
103
 
105
104
  if (isGroupedBatch(message)) {
106
105
  // We should be awaiting a new batch (batchStartCsn undefined)
107
- assert(this.batchStartCsn === undefined, "Grouped batch interrupting another batch");
108
106
  assert(
109
- this.processorBatch.length === 0,
110
- "Processor batch should be empty on grouped batch",
107
+ this.batchStartCsn === undefined,
108
+ 0x9d3 /* Grouped batch interrupting another batch */,
111
109
  );
112
110
  return {
113
111
  messages: this.opGroupingManager.ungroupOp(message).map(unpack),
@@ -119,20 +117,8 @@ export class RemoteMessageProcessor {
119
117
 
120
118
  // Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked
121
119
  unpackRuntimeMessage(message);
122
- this.processorBatch.push(message as InboundSequencedContainerRuntimeMessage);
123
-
124
- // this.batchStartCsn is undefined only if we have processed all messages in the batch.
125
- // If it's still defined, we're still in the middle of a batch, so we return nothing, letting
126
- // containerRuntime know that we're waiting for more messages to complete the batch.
127
- if (this.batchStartCsn !== undefined) {
128
- // batch not yet complete
129
- return undefined;
130
- }
131
-
132
- const messages = [...this.processorBatch];
133
- this.processorBatch.length = 0;
134
120
  return {
135
- messages,
121
+ messages: [message as InboundSequencedContainerRuntimeMessageOrSystemMessage],
136
122
  batchStartCsn,
137
123
  };
138
124
  }
@@ -146,7 +132,7 @@ export class RemoteMessageProcessor {
146
132
  const batchMetadataFlag = asBatchMetadata(message.metadata)?.batch;
147
133
  if (this.batchStartCsn === undefined) {
148
134
  // We are waiting for a new batch
149
- assert(batchMetadataFlag !== false, "Unexpected batch end marker");
135
+ assert(batchMetadataFlag !== false, 0x9d5 /* Unexpected batch end marker */);
150
136
 
151
137
  // Start of a new multi-message batch
152
138
  if (batchMetadataFlag === true) {
@@ -162,7 +148,7 @@ export class RemoteMessageProcessor {
162
148
  // We are in the middle or end of an existing multi-message batch. Return the current batchStartCsn
163
149
  const batchStartCsn = this.batchStartCsn;
164
150
 
165
- assert(batchMetadataFlag !== true, "Unexpected batch start marker");
151
+ assert(batchMetadataFlag !== true, 0x9d6 /* Unexpected batch start marker */);
166
152
  if (batchMetadataFlag === false) {
167
153
  // Batch end? Then get ready for the next batch to start
168
154
  this.batchStartCsn = undefined;
@@ -173,12 +159,27 @@ export class RemoteMessageProcessor {
173
159
  }
174
160
 
175
161
  /** Takes an incoming message and if the contents is a string, JSON.parse's it in place */
176
- function ensureContentsDeserialized(mutableMessage: ISequencedDocumentMessage): void {
162
+ export function ensureContentsDeserialized(
163
+ mutableMessage: ISequencedDocumentMessage,
164
+ modernRuntimeMessage: boolean,
165
+ logLegacyCase: (codePath: string) => void,
166
+ ): void {
177
167
  // back-compat: ADO #1385: eventually should become unconditional, but only for runtime messages!
178
168
  // System message may have no contents, or in some cases (mostly for back-compat) they may have actual objects.
179
169
  // Old ops may contain empty string (I assume noops).
170
+ let parsedJsonContents: boolean;
180
171
  if (typeof mutableMessage.contents === "string" && mutableMessage.contents !== "") {
181
172
  mutableMessage.contents = JSON.parse(mutableMessage.contents);
173
+ parsedJsonContents = true;
174
+ } else {
175
+ parsedJsonContents = false;
176
+ }
177
+
178
+ // We expect Modern Runtime Messages to have JSON serialized contents,
179
+ // and all other messages not to (system messages and legacy runtime messages without outer "op" type envelope)
180
+ // Let's observe if we are wrong about this to learn about these cases.
181
+ if (modernRuntimeMessage !== parsedJsonContents) {
182
+ logLegacyCase("ensureContentsDeserialized_unexpectedContentsType");
182
183
  }
183
184
  }
184
185
 
@@ -214,7 +215,10 @@ function unpack(message: ISequencedDocumentMessage): InboundSequencedContainerRu
214
215
  *
215
216
  * @internal
216
217
  */
217
- export function unpackRuntimeMessage(message: ISequencedDocumentMessage): boolean {
218
+ export function unpackRuntimeMessage(
219
+ message: ISequencedDocumentMessage,
220
+ logLegacyCase: (codePath: string) => void = () => {},
221
+ ): boolean {
218
222
  if (message.type !== MessageType.Operation) {
219
223
  // Legacy format, but it's already "unpacked",
220
224
  // i.e. message.type is actually ContainerMessageType.
@@ -230,6 +234,7 @@ export function unpackRuntimeMessage(message: ISequencedDocumentMessage): boolea
230
234
  (message.contents as { type?: unknown }).type === undefined
231
235
  ) {
232
236
  message.type = ContainerMessageType.FluidDataStoreOp;
237
+ logLegacyCase("unpackRuntimeMessage_contentsWithAddress");
233
238
  } else {
234
239
  // new format
235
240
  unpack(message);
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.1.0-281041";
9
+ export const pkgVersion = "2.1.1";
@@ -16,7 +16,7 @@ import {
16
16
  import Deque from "double-ended-queue";
17
17
  import { v4 as uuid } from "uuid";
18
18
 
19
- import { type InboundSequencedContainerRuntimeMessage } from "./messageTypes.js";
19
+ import { InboundSequencedContainerRuntimeMessage } from "./messageTypes.js";
20
20
  import { asBatchMetadata, IBatchMetadata } from "./metadata.js";
21
21
  import { BatchId, BatchMessage, generateBatchId } from "./opLifecycle/index.js";
22
22
  import { pkgVersion } from "./packageVersion.js";
@@ -293,25 +293,6 @@ export class PendingStateManager implements IDisposable {
293
293
  }
294
294
  }
295
295
 
296
- /**
297
- * Processes the incoming batch from the server. It verifies that messages are received in the right order and
298
- * that the batch information is correct.
299
- * @param batch - The batch that is being processed.
300
- * @param batchStartCsn - The clientSequenceNumber of the start of this message's batch
301
- */
302
- public processPendingLocalBatch(
303
- batch: InboundSequencedContainerRuntimeMessage[],
304
- batchStartCsn: number,
305
- ): {
306
- message: InboundSequencedContainerRuntimeMessage;
307
- localOpMetadata: unknown;
308
- }[] {
309
- return batch.map((message) => ({
310
- message,
311
- localOpMetadata: this.processPendingLocalMessage(message, batchStartCsn),
312
- }));
313
- }
314
-
315
296
  /**
316
297
  * Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that
317
298
  * the batch information was preserved for batch messages.
@@ -319,7 +300,7 @@ export class PendingStateManager implements IDisposable {
319
300
  * @param batchStartCsn - The clientSequenceNumber of the start of this message's batch (assigned during submit)
320
301
  * (not to be confused with message.clientSequenceNumber - the overwritten value in case of grouped batching)
321
302
  */
322
- private processPendingLocalMessage(
303
+ public processPendingLocalMessage(
323
304
  message: InboundSequencedContainerRuntimeMessage,
324
305
  batchStartCsn: number,
325
306
  ): unknown {