@fluidframework/container-runtime 2.31.0 → 2.32.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 (299) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/container-runtime.test-files.tar +0 -0
  3. package/dist/channelCollection.d.ts +0 -14
  4. package/dist/channelCollection.d.ts.map +1 -1
  5. package/dist/channelCollection.js +10 -25
  6. package/dist/channelCollection.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +16 -9
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +137 -103
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStoreContext.d.ts +1 -5
  12. package/dist/dataStoreContext.d.ts.map +1 -1
  13. package/dist/dataStoreContext.js +0 -8
  14. package/dist/dataStoreContext.js.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -2
  18. package/dist/index.js.map +1 -1
  19. package/dist/messageTypes.d.ts +3 -7
  20. package/dist/messageTypes.d.ts.map +1 -1
  21. package/dist/messageTypes.js.map +1 -1
  22. package/dist/opLifecycle/batchManager.d.ts +4 -4
  23. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  24. package/dist/opLifecycle/batchManager.js +4 -4
  25. package/dist/opLifecycle/batchManager.js.map +1 -1
  26. package/dist/opLifecycle/definitions.d.ts +40 -6
  27. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  28. package/dist/opLifecycle/definitions.js.map +1 -1
  29. package/dist/opLifecycle/index.d.ts +4 -3
  30. package/dist/opLifecycle/index.d.ts.map +1 -1
  31. package/dist/opLifecycle/index.js +4 -3
  32. package/dist/opLifecycle/index.js.map +1 -1
  33. package/dist/opLifecycle/opCompressor.d.ts +10 -11
  34. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  35. package/dist/opLifecycle/opCompressor.js +19 -18
  36. package/dist/opLifecycle/opCompressor.js.map +1 -1
  37. package/dist/opLifecycle/opGroupingManager.d.ts +9 -5
  38. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  39. package/dist/opLifecycle/opGroupingManager.js +18 -22
  40. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  41. package/dist/opLifecycle/opSerialization.d.ts +20 -0
  42. package/dist/opLifecycle/opSerialization.d.ts.map +1 -0
  43. package/dist/opLifecycle/opSerialization.js +40 -0
  44. package/dist/opLifecycle/opSerialization.js.map +1 -0
  45. package/dist/opLifecycle/opSplitter.d.ts +12 -13
  46. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  47. package/dist/opLifecycle/opSplitter.js +13 -13
  48. package/dist/opLifecycle/opSplitter.js.map +1 -1
  49. package/dist/opLifecycle/outbox.d.ts +16 -18
  50. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  51. package/dist/opLifecycle/outbox.js +57 -43
  52. package/dist/opLifecycle/outbox.js.map +1 -1
  53. package/dist/opLifecycle/remoteMessageProcessor.d.ts +0 -7
  54. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  55. package/dist/opLifecycle/remoteMessageProcessor.js +1 -15
  56. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  57. package/dist/packageVersion.d.ts +1 -1
  58. package/dist/packageVersion.js +1 -1
  59. package/dist/packageVersion.js.map +1 -1
  60. package/dist/pendingStateManager.d.ts +2 -2
  61. package/dist/pendingStateManager.d.ts.map +1 -1
  62. package/dist/pendingStateManager.js +1 -1
  63. package/dist/pendingStateManager.js.map +1 -1
  64. package/dist/runtimeLayerCompatState.d.ts.map +1 -1
  65. package/dist/runtimeLayerCompatState.js +6 -5
  66. package/dist/runtimeLayerCompatState.js.map +1 -1
  67. package/dist/summary/index.d.ts +5 -8
  68. package/dist/summary/index.d.ts.map +1 -1
  69. package/dist/summary/index.js +20 -21
  70. package/dist/summary/index.js.map +1 -1
  71. package/dist/summary/orderedClientElection.js +9 -9
  72. package/dist/summary/orderedClientElection.js.map +1 -1
  73. package/dist/summary/summarizerClientElection.d.ts +0 -1
  74. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  75. package/dist/summary/summarizerClientElection.js +3 -3
  76. package/dist/summary/summarizerClientElection.js.map +1 -1
  77. package/dist/summary/summarizerTypes.d.ts +3 -75
  78. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  79. package/dist/summary/summarizerTypes.js +2 -0
  80. package/dist/summary/summarizerTypes.js.map +1 -1
  81. package/{lib/summary/summaryGenerator.d.ts → dist/summary/summarizerUtils.d.ts} +12 -43
  82. package/dist/summary/summarizerUtils.d.ts.map +1 -0
  83. package/dist/summary/summarizerUtils.js +71 -0
  84. package/dist/summary/summarizerUtils.js.map +1 -0
  85. package/dist/summary/summaryDelayLoadedModule/index.d.ts +10 -0
  86. package/dist/summary/summaryDelayLoadedModule/index.d.ts.map +1 -0
  87. package/dist/summary/summaryDelayLoadedModule/index.js +20 -0
  88. package/dist/summary/summaryDelayLoadedModule/index.js.map +1 -0
  89. package/dist/summary/{runWhileConnectedCoordinator.d.ts → summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts} +1 -1
  90. package/dist/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts.map +1 -0
  91. package/dist/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js.map +1 -0
  92. package/dist/summary/{runningSummarizer.d.ts → summaryDelayLoadedModule/runningSummarizer.d.ts} +4 -13
  93. package/dist/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -0
  94. package/dist/summary/{runningSummarizer.js → summaryDelayLoadedModule/runningSummarizer.js} +17 -24
  95. package/dist/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -0
  96. package/dist/summary/{summarizer.d.ts → summaryDelayLoadedModule/summarizer.d.ts} +13 -2
  97. package/dist/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -0
  98. package/dist/summary/{summarizer.js → summaryDelayLoadedModule/summarizer.js} +13 -3
  99. package/dist/summary/summaryDelayLoadedModule/summarizer.js.map +1 -0
  100. package/{lib/summary → dist/summary/summaryDelayLoadedModule}/summarizerHeuristics.d.ts +3 -3
  101. package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts.map +1 -0
  102. package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -0
  103. package/dist/summary/summaryDelayLoadedModule/summaryGenerator.d.ts +36 -0
  104. package/dist/summary/summaryDelayLoadedModule/summaryGenerator.d.ts.map +1 -0
  105. package/dist/summary/{summaryGenerator.js → summaryDelayLoadedModule/summaryGenerator.js} +14 -99
  106. package/dist/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -0
  107. package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts +21 -0
  108. package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts.map +1 -0
  109. package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.js +44 -0
  110. package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.js.map +1 -0
  111. package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts +80 -0
  112. package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts.map +1 -0
  113. package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.js +7 -0
  114. package/dist/summary/summaryDelayLoadedModule/summaryResultTypes.js.map +1 -0
  115. package/dist/summary/summaryHelpers.d.ts +1 -1
  116. package/dist/summary/summaryHelpers.d.ts.map +1 -1
  117. package/dist/summary/summaryHelpers.js +2 -2
  118. package/dist/summary/summaryHelpers.js.map +1 -1
  119. package/dist/summary/summaryManager.d.ts +4 -3
  120. package/dist/summary/summaryManager.d.ts.map +1 -1
  121. package/dist/summary/summaryManager.js +2 -2
  122. package/dist/summary/summaryManager.js.map +1 -1
  123. package/lib/channelCollection.d.ts +0 -14
  124. package/lib/channelCollection.d.ts.map +1 -1
  125. package/lib/channelCollection.js +6 -21
  126. package/lib/channelCollection.js.map +1 -1
  127. package/lib/containerRuntime.d.ts +16 -9
  128. package/lib/containerRuntime.d.ts.map +1 -1
  129. package/lib/containerRuntime.js +140 -106
  130. package/lib/containerRuntime.js.map +1 -1
  131. package/lib/dataStoreContext.d.ts +1 -5
  132. package/lib/dataStoreContext.d.ts.map +1 -1
  133. package/lib/dataStoreContext.js +0 -8
  134. package/lib/dataStoreContext.js.map +1 -1
  135. package/lib/index.d.ts +1 -1
  136. package/lib/index.d.ts.map +1 -1
  137. package/lib/index.js +1 -1
  138. package/lib/index.js.map +1 -1
  139. package/lib/messageTypes.d.ts +3 -7
  140. package/lib/messageTypes.d.ts.map +1 -1
  141. package/lib/messageTypes.js.map +1 -1
  142. package/lib/opLifecycle/batchManager.d.ts +4 -4
  143. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  144. package/lib/opLifecycle/batchManager.js +4 -4
  145. package/lib/opLifecycle/batchManager.js.map +1 -1
  146. package/lib/opLifecycle/definitions.d.ts +40 -6
  147. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  148. package/lib/opLifecycle/definitions.js.map +1 -1
  149. package/lib/opLifecycle/index.d.ts +4 -3
  150. package/lib/opLifecycle/index.d.ts.map +1 -1
  151. package/lib/opLifecycle/index.js +3 -2
  152. package/lib/opLifecycle/index.js.map +1 -1
  153. package/lib/opLifecycle/opCompressor.d.ts +10 -11
  154. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  155. package/lib/opLifecycle/opCompressor.js +20 -19
  156. package/lib/opLifecycle/opCompressor.js.map +1 -1
  157. package/lib/opLifecycle/opGroupingManager.d.ts +9 -5
  158. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  159. package/lib/opLifecycle/opGroupingManager.js +18 -22
  160. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  161. package/lib/opLifecycle/opSerialization.d.ts +20 -0
  162. package/lib/opLifecycle/opSerialization.d.ts.map +1 -0
  163. package/lib/opLifecycle/opSerialization.js +35 -0
  164. package/lib/opLifecycle/opSerialization.js.map +1 -0
  165. package/lib/opLifecycle/opSplitter.d.ts +12 -13
  166. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  167. package/lib/opLifecycle/opSplitter.js +13 -13
  168. package/lib/opLifecycle/opSplitter.js.map +1 -1
  169. package/lib/opLifecycle/outbox.d.ts +16 -18
  170. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  171. package/lib/opLifecycle/outbox.js +56 -41
  172. package/lib/opLifecycle/outbox.js.map +1 -1
  173. package/lib/opLifecycle/remoteMessageProcessor.d.ts +0 -7
  174. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  175. package/lib/opLifecycle/remoteMessageProcessor.js +0 -13
  176. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  177. package/lib/packageVersion.d.ts +1 -1
  178. package/lib/packageVersion.js +1 -1
  179. package/lib/packageVersion.js.map +1 -1
  180. package/lib/pendingStateManager.d.ts +2 -2
  181. package/lib/pendingStateManager.d.ts.map +1 -1
  182. package/lib/pendingStateManager.js +1 -1
  183. package/lib/pendingStateManager.js.map +1 -1
  184. package/lib/runtimeLayerCompatState.d.ts.map +1 -1
  185. package/lib/runtimeLayerCompatState.js +3 -2
  186. package/lib/runtimeLayerCompatState.js.map +1 -1
  187. package/lib/summary/index.d.ts +5 -8
  188. package/lib/summary/index.d.ts.map +1 -1
  189. package/lib/summary/index.js +5 -7
  190. package/lib/summary/index.js.map +1 -1
  191. package/lib/summary/orderedClientElection.js +1 -1
  192. package/lib/summary/orderedClientElection.js.map +1 -1
  193. package/lib/summary/summarizerClientElection.d.ts +0 -1
  194. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  195. package/lib/summary/summarizerClientElection.js +1 -1
  196. package/lib/summary/summarizerClientElection.js.map +1 -1
  197. package/lib/summary/summarizerTypes.d.ts +3 -75
  198. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  199. package/lib/summary/summarizerTypes.js +1 -1
  200. package/lib/summary/summarizerTypes.js.map +1 -1
  201. package/{dist/summary/summaryGenerator.d.ts → lib/summary/summarizerUtils.d.ts} +12 -43
  202. package/lib/summary/summarizerUtils.d.ts.map +1 -0
  203. package/lib/summary/summarizerUtils.js +64 -0
  204. package/lib/summary/summarizerUtils.js.map +1 -0
  205. package/lib/summary/summaryDelayLoadedModule/index.d.ts +10 -0
  206. package/lib/summary/summaryDelayLoadedModule/index.d.ts.map +1 -0
  207. package/lib/summary/summaryDelayLoadedModule/index.js +9 -0
  208. package/lib/summary/summaryDelayLoadedModule/index.js.map +1 -0
  209. package/lib/summary/{runWhileConnectedCoordinator.d.ts → summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts} +1 -1
  210. package/lib/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.d.ts.map +1 -0
  211. package/lib/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js.map +1 -0
  212. package/lib/summary/{runningSummarizer.d.ts → summaryDelayLoadedModule/runningSummarizer.d.ts} +4 -13
  213. package/lib/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -0
  214. package/lib/summary/{runningSummarizer.js → summaryDelayLoadedModule/runningSummarizer.js} +5 -12
  215. package/lib/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -0
  216. package/lib/summary/{summarizer.d.ts → summaryDelayLoadedModule/summarizer.d.ts} +13 -2
  217. package/lib/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -0
  218. package/lib/summary/{summarizer.js → summaryDelayLoadedModule/summarizer.js} +11 -1
  219. package/lib/summary/summaryDelayLoadedModule/summarizer.js.map +1 -0
  220. package/{dist/summary → lib/summary/summaryDelayLoadedModule}/summarizerHeuristics.d.ts +3 -3
  221. package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts.map +1 -0
  222. package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -0
  223. package/lib/summary/summaryDelayLoadedModule/summaryGenerator.d.ts +36 -0
  224. package/lib/summary/summaryDelayLoadedModule/summaryGenerator.d.ts.map +1 -0
  225. package/lib/summary/{summaryGenerator.js → summaryDelayLoadedModule/summaryGenerator.js} +4 -85
  226. package/lib/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -0
  227. package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts +21 -0
  228. package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.d.ts.map +1 -0
  229. package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.js +40 -0
  230. package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.js.map +1 -0
  231. package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts +80 -0
  232. package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.d.ts.map +1 -0
  233. package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.js +6 -0
  234. package/lib/summary/summaryDelayLoadedModule/summaryResultTypes.js.map +1 -0
  235. package/lib/summary/summaryHelpers.d.ts +1 -1
  236. package/lib/summary/summaryHelpers.d.ts.map +1 -1
  237. package/lib/summary/summaryHelpers.js +1 -1
  238. package/lib/summary/summaryHelpers.js.map +1 -1
  239. package/lib/summary/summaryManager.d.ts +4 -3
  240. package/lib/summary/summaryManager.d.ts.map +1 -1
  241. package/lib/summary/summaryManager.js +2 -2
  242. package/lib/summary/summaryManager.js.map +1 -1
  243. package/package.json +21 -20
  244. package/src/channelCollection.ts +5 -20
  245. package/src/containerRuntime.ts +220 -178
  246. package/src/dataStoreContext.ts +0 -11
  247. package/src/index.ts +0 -1
  248. package/src/messageTypes.ts +5 -19
  249. package/src/opLifecycle/batchManager.ts +19 -12
  250. package/src/opLifecycle/definitions.ts +45 -6
  251. package/src/opLifecycle/index.ts +14 -3
  252. package/src/opLifecycle/opCompressor.ts +25 -24
  253. package/src/opLifecycle/opGroupingManager.ts +27 -26
  254. package/src/opLifecycle/opSerialization.ts +46 -0
  255. package/src/opLifecycle/opSplitter.ts +20 -16
  256. package/src/opLifecycle/outbox.ts +101 -66
  257. package/src/opLifecycle/remoteMessageProcessor.ts +0 -17
  258. package/src/packageVersion.ts +1 -1
  259. package/src/pendingStateManager.ts +3 -3
  260. package/src/runtimeLayerCompatState.ts +3 -2
  261. package/src/summary/index.ts +35 -31
  262. package/src/summary/orderedClientElection.ts +1 -1
  263. package/src/summary/summarizerClientElection.ts +1 -2
  264. package/src/summary/summarizerTypes.ts +7 -91
  265. package/src/summary/summarizerUtils.ts +132 -0
  266. package/src/summary/summaryDelayLoadedModule/index.ts +28 -0
  267. package/src/summary/{runWhileConnectedCoordinator.ts → summaryDelayLoadedModule/runWhileConnectedCoordinator.ts} +1 -1
  268. package/src/summary/{runningSummarizer.ts → summaryDelayLoadedModule/runningSummarizer.ts} +13 -28
  269. package/src/summary/{summarizer.ts → summaryDelayLoadedModule/summarizer.ts} +19 -8
  270. package/src/summary/{summarizerHeuristics.ts → summaryDelayLoadedModule/summarizerHeuristics.ts} +3 -3
  271. package/src/summary/{summaryGenerator.ts → summaryDelayLoadedModule/summaryGenerator.ts} +13 -179
  272. package/src/summary/summaryDelayLoadedModule/summaryResultBuilder.ts +70 -0
  273. package/src/summary/summaryDelayLoadedModule/summaryResultTypes.ts +100 -0
  274. package/src/summary/summaryHelpers.ts +6 -6
  275. package/src/summary/summaryManager.ts +8 -6
  276. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +0 -1
  277. package/dist/summary/runWhileConnectedCoordinator.js.map +0 -1
  278. package/dist/summary/runningSummarizer.d.ts.map +0 -1
  279. package/dist/summary/runningSummarizer.js.map +0 -1
  280. package/dist/summary/summarizer.d.ts.map +0 -1
  281. package/dist/summary/summarizer.js.map +0 -1
  282. package/dist/summary/summarizerHeuristics.d.ts.map +0 -1
  283. package/dist/summary/summarizerHeuristics.js.map +0 -1
  284. package/dist/summary/summaryGenerator.d.ts.map +0 -1
  285. package/dist/summary/summaryGenerator.js.map +0 -1
  286. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +0 -1
  287. package/lib/summary/runWhileConnectedCoordinator.js.map +0 -1
  288. package/lib/summary/runningSummarizer.d.ts.map +0 -1
  289. package/lib/summary/runningSummarizer.js.map +0 -1
  290. package/lib/summary/summarizer.d.ts.map +0 -1
  291. package/lib/summary/summarizer.js.map +0 -1
  292. package/lib/summary/summarizerHeuristics.d.ts.map +0 -1
  293. package/lib/summary/summarizerHeuristics.js.map +0 -1
  294. package/lib/summary/summaryGenerator.d.ts.map +0 -1
  295. package/lib/summary/summaryGenerator.js.map +0 -1
  296. /package/dist/summary/{runWhileConnectedCoordinator.js → summaryDelayLoadedModule/runWhileConnectedCoordinator.js} +0 -0
  297. /package/dist/summary/{summarizerHeuristics.js → summaryDelayLoadedModule/summarizerHeuristics.js} +0 -0
  298. /package/lib/summary/{runWhileConnectedCoordinator.js → summaryDelayLoadedModule/runWhileConnectedCoordinator.js} +0 -0
  299. /package/lib/summary/{summarizerHeuristics.js → summaryDelayLoadedModule/summarizerHeuristics.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport {\n\tDataProcessingError,\n\tGenericError,\n\tUsageError,\n\tcreateChildLogger,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { OutboundContainerRuntimeMessage } from \"../messageTypes.js\";\nimport { PendingMessageResubmitData, PendingStateManager } from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\tBatchSequenceNumbers,\n\testimateSocketSize,\n\tsequenceNumbersMatch,\n\ttype BatchId,\n} from \"./batchManager.js\";\nimport { BatchMessage, IBatch, IBatchCheckpoint } from \"./definitions.js\";\nimport { OpCompressor } from \"./opCompressor.js\";\nimport { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { OpSplitter } from \"./opSplitter.js\";\n// eslint-disable-next-line unused-imports/no-unused-imports -- Used by \"@link\" comment annotation below\nimport { ensureContentsDeserialized } from \"./remoteMessageProcessor.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t/**\n\t * The maximum size of a batch that we can send over the wire.\n\t */\n\treadonly maxBatchSizeInBytes: number;\n\t/**\n\t * If true, maybeFlushPartialBatch will flush the batch if the reference sequence number changed\n\t * since the batch started. Otherwise, it will throw in this case (apart from reentrancy which is handled elsewhere).\n\t * Once the new throw-based flow is proved in a production environment, this option will be removed.\n\t */\n\treadonly flushPartialBatches: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly submitBatchFn:\n\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t| undefined;\n\treadonly legacySendBatchFn: (batch: IBatch) => number;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryBaseLogger;\n\treadonly groupingManager: OpGroupingManager;\n\treadonly getCurrentSequenceNumbers: () => BatchSequenceNumbers;\n\treadonly reSubmit: (message: PendingMessageResubmitData) => void;\n\treadonly opReentrancy: () => boolean;\n\treadonly closeContainer: (error?: ICriticalContainerError) => void;\n}\n\n/**\n * Before submitting an op to the Outbox, its contents must be serialized using this function.\n * @remarks - The deserialization on process happens via the function {@link ensureContentsDeserialized}.\n */\nexport function serializeOpContents(contents: OutboundContainerRuntimeMessage): string {\n\treturn JSON.stringify(contents);\n}\n\n/**\n * Temporarily increase the stack limit while executing the provided action.\n * If a negative value is provided for `length`, no stack frames will be collected.\n * If Infinity is provided, all frames will be collected.\n *\n * ADO:4663 - add this to the common packages.\n *\n * @param action - action which returns an error\n * @param length - number of stack frames to collect, 50 if unspecified.\n * @returns the result of the action provided\n */\nexport function getLongStack<T>(action: () => T, length: number = 50): T {\n\t// TODO: better typing here\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment\n\tconst errorObj = Error as any;\n\tif (\n\t\t/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n\t\t// ?? is not logically equivalent when the first clause returns false.\n\t\t(\n\t\t\tObject.getOwnPropertyDescriptor(errorObj, \"stackTraceLimit\") ||\n\t\t\tObject.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), \"stackTraceLimit\")\n\t\t)?.writable !== true\n\t\t/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */\n\t) {\n\t\treturn action();\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\n/**\n * The Outbox collects messages submitted by the ContainerRuntime into a batch,\n * and then flushes the batch when requested.\n *\n * @remarks There are actually multiple independent batches (some are for a specific message type),\n * to support slight variation in semantics for each batch (e.g. support for rebasing or grouping).\n */\nexport class Outbox {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly blobAttachBatch: BatchManager;\n\tprivate readonly idAllocationBatch: BatchManager;\n\tprivate batchRebasesToReport = 5;\n\tprivate rebasing = false;\n\n\t/**\n\t * Track the number of ops which were detected to have a mismatched\n\t * reference sequence number, in order to self-throttle the telemetry events.\n\t *\n\t * This should be removed as part of ADO:2322\n\t */\n\tprivate readonly maxMismatchedOpsToReport = 3;\n\tprivate mismatchedOpsReported = 0;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tthis.logger = createChildLogger({ logger: params.logger, namespace: \"Outbox\" });\n\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled\n\t\t\t? Number.POSITIVE_INFINITY\n\t\t\t: this.params.config.maxBatchSizeInBytes;\n\n\t\tthis.mainBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.idAllocationBatch = new BatchManager({\n\t\t\thardLimit,\n\t\t\tcanRebase: false,\n\t\t\tignoreBatchId: true,\n\t\t});\n\t}\n\n\tpublic get messageCount(): number {\n\t\treturn this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;\n\t}\n\n\tpublic get mainBatchMessageCount(): number {\n\t\treturn this.mainBatch.length;\n\t}\n\n\tpublic get blobAttachBatchMessageCount(): number {\n\t\treturn this.blobAttachBatch.length;\n\t}\n\n\tpublic get idAllocationBatchMessageCount(): number {\n\t\treturn this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\t/**\n\t * Detect whether batching has been interrupted by an incoming message being processed. In this case,\n\t * we will flush the accumulated messages to account for that (if allowed) and create a new batch with the new\n\t * message as the first message. If flushing partial batch is not enabled, we will throw (except for reentrant ops).\n\t * This would indicate we expected this case to be precluded by logic elsewhere.\n\t *\n\t * @remarks - To detect batch interruption, we compare both the reference sequence number\n\t * (i.e. last message processed by DeltaManager) and the client sequence number of the\n\t * last message processed by the ContainerRuntime. In the absence of op reentrancy, this\n\t * pair will remain stable during a single JS turn during which the batch is being built up.\n\t */\n\tprivate maybeFlushPartialBatch(): void {\n\t\tconst mainBatchSeqNums = this.mainBatch.sequenceNumbers;\n\t\tconst blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;\n\t\tconst idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;\n\t\tassert(\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\t\t\t\tsequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums),\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tconst currentSequenceNumbers = this.params.getCurrentSequenceNumbers();\n\n\t\tif (\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\t// Reference and/or Client sequence number will be advancing while processing this batch,\n\t\t// so we can't use this check to detect wrongdoing. But we will still log via telemetry.\n\t\t// This is rare, and the reentrancy will be handled during Flush.\n\t\tconst expectedDueToReentrancy = this.isContextReentrant();\n\n\t\tconst errorWrapper = new Lazy(() =>\n\t\t\tgetLongStack(() =>\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"Sequence numbers advanced as if ops were processed while a batch is accumulating\",\n\t\t\t\t\t\"outboxSequenceNumberCoherencyCheck\",\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\t// Only log error if this is truly unexpected\n\t\t\t\t\tcategory:\n\t\t\t\t\t\texpectedDueToReentrancy || this.params.config.flushPartialBatches\n\t\t\t\t\t\t\t? \"generic\"\n\t\t\t\t\t\t\t: \"error\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tData_details: {\n\t\t\t\t\t\texpectedDueToReentrancy,\n\t\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\terrorWrapper.value,\n\t\t\t);\n\t\t}\n\n\t\t// If we're configured to flush partial batches, do that now and return (don't throw)\n\t\tif (this.params.config.flushPartialBatches) {\n\t\t\tthis.flushAll();\n\t\t\treturn;\n\t\t}\n\n\t\t// If we are in a reentrant context, we know this can happen without causing any harm.\n\t\tif (expectedDueToReentrancy) {\n\t\t\treturn;\n\t\t}\n\n\t\tthrow errorWrapper.value;\n\t}\n\n\tpublic submit(message: BatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: BatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\t}\n\n\tpublic submitIdAllocation(message: BatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t}\n\n\tprivate addMessageToBatchManager(batchManager: BatchManager, message: BatchMessage): void {\n\t\tif (\n\t\t\t!batchManager.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: batchManager.contentSizeInBytes,\n\t\t\t\tcount: batchManager.length,\n\t\t\t\tlimit: batchManager.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Flush all the batches to the ordering service.\n\t * This method is expected to be called at the end of a batch.\n\t * @param resubmittingBatchId - If defined, indicates this is a resubmission of a batch\n\t * with the given Batch ID, which must be preserved\n\t */\n\tpublic flush(resubmittingBatchId?: BatchId): void {\n\t\tif (this.isContextReentrant()) {\n\t\t\tconst error = new UsageError(\"Flushing is not supported inside DDS event handlers\");\n\t\t\tthis.params.closeContainer(error);\n\t\t\tthrow error;\n\t\t}\n\n\t\tthis.flushAll(resubmittingBatchId);\n\t}\n\n\tprivate flushAll(resubmittingBatchId?: BatchId): void {\n\t\tconst allBatchesEmpty =\n\t\t\tthis.idAllocationBatch.empty && this.blobAttachBatch.empty && this.mainBatch.empty;\n\t\tif (allBatchesEmpty) {\n\t\t\t// If we're resubmitting and all batches are empty, we need to flush an empty batch.\n\t\t\t// Note that we currently resubmit one batch at a time, so on resubmit, 2 of the 3 batches will *always* be empty.\n\t\t\t// It's theoretically possible that we don't *need* to resubmit this empty batch, and in those cases, it'll safely be ignored\n\t\t\t// by the rest of the system, including remote clients.\n\t\t\t// 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.\n\t\t\tif (resubmittingBatchId) {\n\t\t\t\tthis.flushEmptyBatch(resubmittingBatchId);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Don't use resubmittingBatchId for idAllocationBatch.\n\t\t// ID Allocation messages are not directly resubmitted so we don't want to reuse the batch ID.\n\t\tthis.flushInternal(this.idAllocationBatch);\n\t\tthis.flushInternal(\n\t\t\tthis.blobAttachBatch,\n\t\t\ttrue /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t\tthis.flushInternal(\n\t\t\tthis.mainBatch,\n\t\t\tfalse /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t}\n\n\tprivate flushEmptyBatch(resubmittingBatchId: BatchId): void {\n\t\tconst referenceSequenceNumber =\n\t\t\tthis.params.getCurrentSequenceNumbers().referenceSequenceNumber;\n\t\tassert(\n\t\t\treferenceSequenceNumber !== undefined,\n\t\t\t0xa01 /* reference sequence number should be defined */,\n\t\t);\n\t\tconst emptyGroupedBatch = this.params.groupingManager.createEmptyGroupedBatch(\n\t\t\tresubmittingBatchId,\n\t\t\treferenceSequenceNumber,\n\t\t);\n\t\tlet clientSequenceNumber: number | undefined;\n\t\tif (this.params.shouldSend()) {\n\t\t\tclientSequenceNumber = this.sendBatch(emptyGroupedBatch);\n\t\t}\n\t\tthis.params.pendingStateManager.onFlushBatch(\n\t\t\temptyGroupedBatch.messages, // This is the single empty Grouped Batch message\n\t\t\tclientSequenceNumber,\n\t\t);\n\t\treturn;\n\t}\n\n\tprivate flushInternal(\n\t\tbatchManager: BatchManager,\n\t\tdisableGroupedBatching: boolean = false,\n\t\tresubmittingBatchId?: BatchId,\n\t): void {\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch(resubmittingBatchId);\n\t\tconst shouldGroup =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);\n\t\tif (batchManager.options.canRebase && rawBatch.hasReentrantOps === true && shouldGroup) {\n\t\t\tassert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);\n\t\t\t// If a batch contains reentrant ops (ops created as a result from processing another op)\n\t\t\t// it needs to be rebased so that we can ensure consistent reference sequence numbers\n\t\t\t// and eventual consistency at the DDS level.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\tlet clientSequenceNumber: number | undefined;\n\t\t// Did we disconnect? (i.e. is shouldSend false?)\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\t// Because flush() is a task that executes async (on clean stack), we can get here in disconnected state.\n\t\tif (this.params.shouldSend()) {\n\t\t\tconst processedBatch = disableGroupedBatching\n\t\t\t\t? rawBatch\n\t\t\t\t: this.compressAndChunkBatch(\n\t\t\t\t\t\tshouldGroup ? this.params.groupingManager.groupBatch(rawBatch) : rawBatch,\n\t\t\t\t\t);\n\t\t\tclientSequenceNumber = this.sendBatch(processedBatch);\n\t\t\tassert(\n\t\t\t\tclientSequenceNumber === undefined || clientSequenceNumber >= 0,\n\t\t\t\t0x9d2 /* unexpected negative clientSequenceNumber (empty batch should yield undefined) */,\n\t\t\t);\n\t\t}\n\n\t\tthis.params.pendingStateManager.onFlushBatch(\n\t\t\trawBatch.messages,\n\t\t\tclientSequenceNumber,\n\t\t\tbatchManager.options.ignoreBatchId,\n\t\t);\n\t}\n\n\t/**\n\t * Rebases a batch. All the ops in the batch are resubmitted to the runtime and\n\t * they will end up back in the same batch manager they were flushed from and subsequently flushed.\n\t *\n\t * @param rawBatch - the batch to be rebased\n\t */\n\tprivate rebase(rawBatch: IBatch, batchManager: BatchManager): void {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\t\tassert(batchManager.options.canRebase, 0x9a7 /* BatchManager does not support rebase */);\n\n\t\tthis.rebasing = true;\n\t\tfor (const message of rawBatch.messages) {\n\t\t\tthis.params.reSubmit({\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tcontent: message.contents!,\n\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\topMetadata: message.metadata,\n\t\t\t});\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"BatchRebase\",\n\t\t\t\t\tlength: rawBatch.messages.length,\n\t\t\t\t\treferenceSequenceNumber: rawBatch.referenceSequenceNumber,\n\t\t\t\t},\n\t\t\t\tnew UsageError(\"BatchRebase\"),\n\t\t\t);\n\t\t\tthis.batchRebasesToReport--;\n\t\t}\n\n\t\tthis.flushInternal(batchManager);\n\t\tthis.rebasing = false;\n\t}\n\n\tprivate isContextReentrant(): boolean {\n\t\treturn this.params.opReentrancy() && !this.rebasing;\n\t}\n\n\t/**\n\t * As necessary and enabled, compresses and chunks the given batch.\n\t *\n\t * @remarks - If chunking happens, a side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.\n\t *\n\t * @param batch - Raw or Grouped batch to consider for compression/chunking\n\t * @returns Either (A) the original batch, (B) a compressed batch (same length as original)\n\t * or (C) a batch containing the last chunk.\n\t */\n\tprivate compressAndChunkBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.messages.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tbatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined ||\n\t\t\t!this.params.groupingManager.groupedBatchingEnabled()\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes\n\t\t\t\t? compressedBatch\n\t\t\t\t: this.params.splitter.splitFirstBatchMessage(compressedBatch);\n\t\t}\n\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\t\tcount: compressedBatch.messages.length,\n\t\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t * @returns the clientSequenceNumber of the start of the batch, or undefined if nothing was sent\n\t */\n\tprivate sendBatch(batch: IBatch): number | undefined {\n\t\tconst length = batch.messages.length;\n\t\tif (length === 0) {\n\t\t\treturn undefined; // Nothing submitted\n\t\t}\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tif (socketSize >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"LargeBatch\",\n\t\t\t\tlength: batch.messages.length,\n\t\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\t\tsocketSize,\n\t\t\t});\n\t\t}\n\n\t\tlet clientSequenceNumber: number;\n\t\tif (this.params.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tassert(\n\t\t\t\tbatch.messages[0].compression === undefined,\n\t\t\t\t0x5a6 /* Compression should not have happened if the loader does not support it */,\n\t\t\t);\n\n\t\t\tclientSequenceNumber = this.params.legacySendBatchFn(batch);\n\t\t} else {\n\t\t\tassert(batch.referenceSequenceNumber !== undefined, 0x58e /* Batch must not be empty */);\n\t\t\tclientSequenceNumber = this.params.submitBatchFn(\n\t\t\t\tbatch.messages.map<IBatchMessage>((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t})),\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\t// Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.\n\t\tclientSequenceNumber -= length - 1;\n\t\tassert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);\n\t\treturn clientSequenceNumber;\n\t}\n\n\t/**\n\t * Gets a checkpoint object per batch that facilitates iterating over the batch messages when rolling back.\n\t */\n\tpublic getBatchCheckpoints(): {\n\t\tmainBatch: IBatchCheckpoint;\n\t\tidAllocationBatch: IBatchCheckpoint;\n\t\tblobAttachBatch: IBatchCheckpoint;\n\t} {\n\t\t// This variable is declared with a specific type so that we have a standard import of the IBatchCheckpoint type.\n\t\t// When the type is inferred, the generated .d.ts uses a dynamic import which doesn't resolve.\n\t\tconst mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();\n\t\treturn {\n\t\t\tmainBatch,\n\t\t\tidAllocationBatch: this.idAllocationBatch.checkpoint(),\n\t\t\tblobAttachBatch: this.blobAttachBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IBatchMessage } from \"@fluidframework/container-definitions/internal\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport {\n\tDataProcessingError,\n\tGenericError,\n\tUsageError,\n\tcreateChildLogger,\n\ttype ITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ICompressionRuntimeOptions } from \"../containerRuntime.js\";\nimport { PendingMessageResubmitData, PendingStateManager } from \"../pendingStateManager.js\";\n\nimport {\n\tBatchManager,\n\tBatchSequenceNumbers,\n\testimateSocketSize,\n\tsequenceNumbersMatch,\n\ttype BatchId,\n} from \"./batchManager.js\";\nimport {\n\tLocalBatchMessage,\n\tIBatchCheckpoint,\n\ttype OutboundBatchMessage,\n\ttype OutboundSingletonBatch,\n\ttype LocalBatch,\n\ttype OutboundBatch,\n} from \"./definitions.js\";\nimport { OpCompressor } from \"./opCompressor.js\";\nimport { OpGroupingManager } from \"./opGroupingManager.js\";\nimport { OpSplitter } from \"./opSplitter.js\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t/**\n\t * The maximum size of a batch that we can send over the wire.\n\t */\n\treadonly maxBatchSizeInBytes: number;\n\t/**\n\t * If true, maybeFlushPartialBatch will flush the batch if the reference sequence number changed\n\t * since the batch started. Otherwise, it will throw in this case (apart from reentrancy which is handled elsewhere).\n\t * Once the new throw-based flow is proved in a production environment, this option will be removed.\n\t */\n\treadonly flushPartialBatches: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly submitBatchFn:\n\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t| undefined;\n\treadonly legacySendBatchFn: (batch: OutboundBatch) => number;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryBaseLogger;\n\treadonly groupingManager: OpGroupingManager;\n\treadonly getCurrentSequenceNumbers: () => BatchSequenceNumbers;\n\treadonly reSubmit: (message: PendingMessageResubmitData) => void;\n\treadonly opReentrancy: () => boolean;\n}\n\n/**\n * Temporarily increase the stack limit while executing the provided action.\n * If a negative value is provided for `length`, no stack frames will be collected.\n * If Infinity is provided, all frames will be collected.\n *\n * ADO:4663 - add this to the common packages.\n *\n * @param action - action which returns an error\n * @param length - number of stack frames to collect, 50 if unspecified.\n * @returns the result of the action provided\n */\nexport function getLongStack<T>(action: () => T, length: number = 50): T {\n\t// TODO: better typing here\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment\n\tconst errorObj = Error as any;\n\tif (\n\t\t/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n\t\t// ?? is not logically equivalent when the first clause returns false.\n\t\t(\n\t\t\tObject.getOwnPropertyDescriptor(errorObj, \"stackTraceLimit\") ||\n\t\t\tObject.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), \"stackTraceLimit\")\n\t\t)?.writable !== true\n\t\t/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */\n\t) {\n\t\treturn action();\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\tconst originalStackTraceLimit = errorObj.stackTraceLimit;\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\terrorObj.stackTraceLimit = length;\n\t\treturn action();\n\t} finally {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n\t\terrorObj.stackTraceLimit = originalStackTraceLimit;\n\t}\n}\n\n/**\n * The Outbox collects messages submitted by the ContainerRuntime into a batch,\n * and then flushes the batch when requested.\n *\n * @remarks There are actually multiple independent batches (some are for a specific message type),\n * to support slight variation in semantics for each batch (e.g. support for rebasing or grouping).\n */\nexport class Outbox {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly blobAttachBatch: BatchManager;\n\tprivate readonly idAllocationBatch: BatchManager;\n\tprivate batchRebasesToReport = 5;\n\tprivate rebasing = false;\n\n\t/**\n\t * Track the number of ops which were detected to have a mismatched\n\t * reference sequence number, in order to self-throttle the telemetry events.\n\t *\n\t * This should be removed as part of ADO:2322\n\t */\n\tprivate readonly maxMismatchedOpsToReport = 3;\n\tprivate mismatchedOpsReported = 0;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tthis.logger = createChildLogger({ logger: params.logger, namespace: \"Outbox\" });\n\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled\n\t\t\t? Number.POSITIVE_INFINITY\n\t\t\t: this.params.config.maxBatchSizeInBytes;\n\n\t\tthis.mainBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });\n\t\tthis.idAllocationBatch = new BatchManager({\n\t\t\thardLimit,\n\t\t\tcanRebase: false,\n\t\t\tignoreBatchId: true,\n\t\t});\n\t}\n\n\tpublic get messageCount(): number {\n\t\treturn this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;\n\t}\n\n\tpublic get mainBatchMessageCount(): number {\n\t\treturn this.mainBatch.length;\n\t}\n\n\tpublic get blobAttachBatchMessageCount(): number {\n\t\treturn this.blobAttachBatch.length;\n\t}\n\n\tpublic get idAllocationBatchMessageCount(): number {\n\t\treturn this.idAllocationBatch.length;\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.messageCount === 0;\n\t}\n\n\t/**\n\t * Detect whether batching has been interrupted by an incoming message being processed. In this case,\n\t * we will flush the accumulated messages to account for that (if allowed) and create a new batch with the new\n\t * message as the first message. If flushing partial batch is not enabled, we will throw (except for reentrant ops).\n\t * This would indicate we expected this case to be precluded by logic elsewhere.\n\t *\n\t * @remarks - To detect batch interruption, we compare both the reference sequence number\n\t * (i.e. last message processed by DeltaManager) and the client sequence number of the\n\t * last message processed by the ContainerRuntime. In the absence of op reentrancy, this\n\t * pair will remain stable during a single JS turn during which the batch is being built up.\n\t */\n\tprivate maybeFlushPartialBatch(): void {\n\t\tconst mainBatchSeqNums = this.mainBatch.sequenceNumbers;\n\t\tconst blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;\n\t\tconst idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;\n\t\tassert(\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&\n\t\t\t\tsequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums),\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tconst currentSequenceNumbers = this.params.getCurrentSequenceNumbers();\n\n\t\tif (\n\t\t\tsequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&\n\t\t\tsequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\t// Reference and/or Client sequence number will be advancing while processing this batch,\n\t\t// so we can't use this check to detect wrongdoing. But we will still log via telemetry.\n\t\t// This is rare, and the reentrancy will be handled during Flush.\n\t\tconst expectedDueToReentrancy = this.isContextReentrant();\n\n\t\tconst errorWrapper = new Lazy(() =>\n\t\t\tgetLongStack(() =>\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"Sequence numbers advanced as if ops were processed while a batch is accumulating\",\n\t\t\t\t\t\"outboxSequenceNumberCoherencyCheck\",\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\t// Only log error if this is truly unexpected\n\t\t\t\t\tcategory:\n\t\t\t\t\t\texpectedDueToReentrancy || this.params.config.flushPartialBatches\n\t\t\t\t\t\t\t? \"generic\"\n\t\t\t\t\t\t\t: \"error\",\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tData_details: {\n\t\t\t\t\t\texpectedDueToReentrancy,\n\t\t\t\t\t\tmainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tmainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tblobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,\n\t\t\t\t\t\tblobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,\n\t\t\t\t\t\tcurrentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,\n\t\t\t\t\t\tcurrentClientSequenceNumber: currentSequenceNumbers.clientSequenceNumber,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\terrorWrapper.value,\n\t\t\t);\n\t\t}\n\n\t\t// If we're configured to flush partial batches, do that now and return (don't throw)\n\t\tif (this.params.config.flushPartialBatches) {\n\t\t\tthis.flushAll();\n\t\t\treturn;\n\t\t}\n\n\t\t// If we are in a reentrant context, we know this can happen without causing any harm.\n\t\tif (expectedDueToReentrancy) {\n\t\t\treturn;\n\t\t}\n\n\t\tthrow errorWrapper.value;\n\t}\n\n\tpublic submit(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.mainBatch, message);\n\t}\n\n\tpublic submitBlobAttach(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.blobAttachBatch, message);\n\t}\n\n\tpublic submitIdAllocation(message: LocalBatchMessage): void {\n\t\tthis.maybeFlushPartialBatch();\n\n\t\tthis.addMessageToBatchManager(this.idAllocationBatch, message);\n\t}\n\n\tprivate addMessageToBatchManager(\n\t\tbatchManager: BatchManager,\n\t\tmessage: LocalBatchMessage,\n\t): void {\n\t\tif (\n\t\t\t!batchManager.push(\n\t\t\t\tmessage,\n\t\t\t\tthis.isContextReentrant(),\n\t\t\t\tthis.params.getCurrentSequenceNumbers().clientSequenceNumber,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.serializedOp?.length ?? 0,\n\t\t\t\tbatchSize: batchManager.contentSizeInBytes,\n\t\t\t\tcount: batchManager.length,\n\t\t\t\tlimit: batchManager.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Flush all the batches to the ordering service.\n\t * This method is expected to be called at the end of a batch.\n\t *\n\t * @throws If called from a reentrant context, or if the batch being flushed is too large.\n\t * @param resubmittingBatchId - If defined, indicates this is a resubmission of a batch\n\t * with the given Batch ID, which must be preserved\n\t */\n\tpublic flush(resubmittingBatchId?: BatchId): void {\n\t\tassert(\n\t\t\t!this.isContextReentrant(),\n\t\t\t0xb7b /* Flushing must not happen while incoming changes are being processed */,\n\t\t);\n\n\t\tthis.flushAll(resubmittingBatchId);\n\t}\n\n\tprivate flushAll(resubmittingBatchId?: BatchId): void {\n\t\tconst allBatchesEmpty =\n\t\t\tthis.idAllocationBatch.empty && this.blobAttachBatch.empty && this.mainBatch.empty;\n\t\tif (allBatchesEmpty) {\n\t\t\t// If we're resubmitting and all batches are empty, we need to flush an empty batch.\n\t\t\t// Note that we currently resubmit one batch at a time, so on resubmit, 2 of the 3 batches will *always* be empty.\n\t\t\t// It's theoretically possible that we don't *need* to resubmit this empty batch, and in those cases, it'll safely be ignored\n\t\t\t// by the rest of the system, including remote clients.\n\t\t\t// 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.\n\t\t\tif (resubmittingBatchId) {\n\t\t\t\tthis.flushEmptyBatch(resubmittingBatchId);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Don't use resubmittingBatchId for idAllocationBatch.\n\t\t// ID Allocation messages are not directly resubmitted so we don't want to reuse the batch ID.\n\t\tthis.flushInternal(this.idAllocationBatch);\n\t\tthis.flushInternal(\n\t\t\tthis.blobAttachBatch,\n\t\t\ttrue /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t\tthis.flushInternal(\n\t\t\tthis.mainBatch,\n\t\t\tfalse /* disableGroupedBatching */,\n\t\t\tresubmittingBatchId,\n\t\t);\n\t}\n\n\tprivate flushEmptyBatch(resubmittingBatchId: BatchId): void {\n\t\tconst referenceSequenceNumber =\n\t\t\tthis.params.getCurrentSequenceNumbers().referenceSequenceNumber;\n\t\tassert(\n\t\t\treferenceSequenceNumber !== undefined,\n\t\t\t0xa01 /* reference sequence number should be defined */,\n\t\t);\n\t\tconst { outboundBatch, placeholderMessage } =\n\t\t\tthis.params.groupingManager.createEmptyGroupedBatch(\n\t\t\t\tresubmittingBatchId,\n\t\t\t\treferenceSequenceNumber,\n\t\t\t);\n\t\tlet clientSequenceNumber: number | undefined;\n\t\tif (this.params.shouldSend()) {\n\t\t\tclientSequenceNumber = this.sendBatch(outboundBatch);\n\t\t}\n\n\t\t// Push the empty batch placeholder to the PendingStateManager\n\t\tthis.params.pendingStateManager.onFlushBatch(\n\t\t\t[{ ...placeholderMessage, serializedOp: \"\", contents: undefined }], // placeholder message - serializedOp will never be used\n\t\t\tclientSequenceNumber,\n\t\t);\n\t\treturn;\n\t}\n\n\tprivate flushInternal(\n\t\tbatchManager: BatchManager,\n\t\tdisableGroupedBatching: boolean = false,\n\t\tresubmittingBatchId?: BatchId,\n\t): void {\n\t\tif (batchManager.empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawBatch = batchManager.popBatch(resubmittingBatchId);\n\t\tconst groupingEnabled =\n\t\t\t!disableGroupedBatching && this.params.groupingManager.groupedBatchingEnabled();\n\t\tif (\n\t\t\tbatchManager.options.canRebase &&\n\t\t\trawBatch.hasReentrantOps === true &&\n\t\t\t// NOTE: This is too restrictive. We should rebase for any reentrant op, not just if it's going to be a grouped batch\n\t\t\t// However there is some test that is depending on this behavior so we haven't removed these conditions yet. See AB#33427\n\t\t\tgroupingEnabled &&\n\t\t\trawBatch.messages.length > 1\n\t\t) {\n\t\t\tassert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);\n\t\t\t// If a batch contains reentrant ops (ops created as a result from processing another op)\n\t\t\t// it needs to be rebased so that we can ensure consistent reference sequence numbers\n\t\t\t// and eventual consistency at the DDS level.\n\t\t\tthis.rebase(rawBatch, batchManager);\n\t\t\treturn;\n\t\t}\n\n\t\tlet clientSequenceNumber: number | undefined;\n\t\t// Did we disconnect? (i.e. is shouldSend false?)\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\t// Because flush() is a task that executes async (on clean stack), we can get here in disconnected state.\n\t\tif (this.params.shouldSend()) {\n\t\t\tconst virtualizedBatch = this.virtualizeBatch(rawBatch, groupingEnabled);\n\n\t\t\tclientSequenceNumber = this.sendBatch(virtualizedBatch);\n\t\t\tassert(\n\t\t\t\tclientSequenceNumber === undefined || clientSequenceNumber >= 0,\n\t\t\t\t0x9d2 /* unexpected negative clientSequenceNumber (empty batch should yield undefined) */,\n\t\t\t);\n\t\t}\n\n\t\tthis.params.pendingStateManager.onFlushBatch(\n\t\t\trawBatch.messages,\n\t\t\tclientSequenceNumber,\n\t\t\tbatchManager.options.ignoreBatchId,\n\t\t);\n\t}\n\n\t/**\n\t * Rebases a batch. All the ops in the batch are resubmitted to the runtime and\n\t * they will end up back in the same batch manager they were flushed from and subsequently flushed.\n\t *\n\t * @param rawBatch - the batch to be rebased\n\t */\n\tprivate rebase(rawBatch: LocalBatch, batchManager: BatchManager): void {\n\t\tassert(!this.rebasing, 0x6fb /* Reentrancy */);\n\t\tassert(batchManager.options.canRebase, 0x9a7 /* BatchManager does not support rebase */);\n\n\t\tthis.rebasing = true;\n\t\tfor (const message of rawBatch.messages) {\n\t\t\tthis.params.reSubmit({\n\t\t\t\tcontent: message.serializedOp,\n\t\t\t\tlocalOpMetadata: message.localOpMetadata,\n\t\t\t\topMetadata: message.metadata,\n\t\t\t});\n\t\t}\n\n\t\tif (this.batchRebasesToReport > 0) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"BatchRebase\",\n\t\t\t\t\tlength: rawBatch.messages.length,\n\t\t\t\t\treferenceSequenceNumber: rawBatch.referenceSequenceNumber,\n\t\t\t\t},\n\t\t\t\tnew UsageError(\"BatchRebase\"),\n\t\t\t);\n\t\t\tthis.batchRebasesToReport--;\n\t\t}\n\n\t\tthis.flushInternal(batchManager);\n\t\tthis.rebasing = false;\n\t}\n\n\tprivate isContextReentrant(): boolean {\n\t\treturn this.params.opReentrancy() && !this.rebasing;\n\t}\n\n\t/**\n\t * As necessary and enabled, groups / compresses / chunks the given batch.\n\t *\n\t * @remarks - If chunking happens, a side effect here is that 1 or more chunks are queued immediately for sending in next JS turn.\n\t *\n\t * @param localBatch - Local Batch to be virtualized - i.e. transformed into an Outbound Batch\n\t * @param groupingEnabled - If true, Grouped batching is enabled.\n\t * @returns One of the following:\n\t * - (A) The original batch (Based on what's enabled)\n\t * - (B) A grouped batch (it's a singleton batch)\n\t * - (C) A compressed singleton batch\n\t * - (D) A singleton batch containing the last chunk.\n\t */\n\tprivate virtualizeBatch(localBatch: LocalBatch, groupingEnabled: boolean): OutboundBatch {\n\t\t// Shallow copy the local batch, updating the messages to be outbound messages\n\t\tconst originalBatch: OutboundBatch = {\n\t\t\t...localBatch,\n\t\t\tmessages: localBatch.messages.map<OutboundBatchMessage>(\n\t\t\t\t({ serializedOp, ...message }) => ({\n\t\t\t\t\tcontents: serializedOp,\n\t\t\t\t\t...message,\n\t\t\t\t}),\n\t\t\t),\n\t\t};\n\n\t\tconst originalOrGroupedBatch = groupingEnabled\n\t\t\t? this.params.groupingManager.groupBatch(originalBatch)\n\t\t\t: originalBatch;\n\n\t\tif (originalOrGroupedBatch.messages.length !== 1) {\n\t\t\t// Compression requires a single message, so return early otherwise.\n\t\t\treturn originalOrGroupedBatch;\n\t\t}\n\n\t\t// Regardless of whether we grouped or not, we now have a batch with a single message.\n\t\t// Now proceed to compress/chunk it if necessary.\n\t\tconst singletonBatch = originalOrGroupedBatch as OutboundSingletonBatch;\n\n\t\tif (\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tsingletonBatch.contentSizeInBytes ||\n\t\t\tthis.params.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if compression is disabled, unnecessary or unsupported.\n\t\t\treturn singletonBatch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(singletonBatch);\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes\n\t\t\t\t? compressedBatch\n\t\t\t\t: this.params.splitter.splitSingletonBatchMessage(compressedBatch);\n\t\t}\n\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\"BatchTooLarge\",\n\t\t\t\t\"compressionInsufficient\",\n\t\t\t\t/* sequencedMessage */ undefined,\n\t\t\t\t{\n\t\t\t\t\tbatchSize: singletonBatch.contentSizeInBytes,\n\t\t\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\t\t\tcount: compressedBatch.messages.length,\n\t\t\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\t\tsocketSize: estimateSocketSize(singletonBatch),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t * @returns the clientSequenceNumber of the start of the batch, or undefined if nothing was sent\n\t */\n\tprivate sendBatch(batch: OutboundBatch): number | undefined {\n\t\tconst length = batch.messages.length;\n\t\tif (length === 0) {\n\t\t\treturn undefined; // Nothing submitted\n\t\t}\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tif (socketSize >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"LargeBatch\",\n\t\t\t\tlength: batch.messages.length,\n\t\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\t\tsocketSize,\n\t\t\t});\n\t\t}\n\n\t\tlet clientSequenceNumber: number;\n\t\tif (this.params.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tassert(\n\t\t\t\tbatch.messages[0].compression === undefined,\n\t\t\t\t0x5a6 /* Compression should not have happened if the loader does not support it */,\n\t\t\t);\n\n\t\t\tclientSequenceNumber = this.params.legacySendBatchFn(batch);\n\t\t} else {\n\t\t\tassert(batch.referenceSequenceNumber !== undefined, 0x58e /* Batch must not be empty */);\n\t\t\tclientSequenceNumber = this.params.submitBatchFn(\n\t\t\t\tbatch.messages.map<IBatchMessage>((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t})),\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\t// Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.\n\t\tclientSequenceNumber -= length - 1;\n\t\tassert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);\n\t\treturn clientSequenceNumber;\n\t}\n\n\t/**\n\t * Gets a checkpoint object per batch that facilitates iterating over the batch messages when rolling back.\n\t */\n\tpublic getBatchCheckpoints(): {\n\t\tmainBatch: IBatchCheckpoint;\n\t\tidAllocationBatch: IBatchCheckpoint;\n\t\tblobAttachBatch: IBatchCheckpoint;\n\t} {\n\t\t// This variable is declared with a specific type so that we have a standard import of the IBatchCheckpoint type.\n\t\t// When the type is inferred, the generated .d.ts uses a dynamic import which doesn't resolve.\n\t\tconst mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();\n\t\treturn {\n\t\t\tmainBatch,\n\t\t\tidAllocationBatch: this.idAllocationBatch.checkpoint(),\n\t\t\tblobAttachBatch: this.blobAttachBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
@@ -99,13 +99,6 @@ export declare class RemoteMessageProcessor {
99
99
  */
100
100
  private getResultBasedOnBatchMetadata;
101
101
  }
102
- /**
103
- * Takes an incoming runtime message JSON.parse's its contents in place, if needed (old Loader does this for us).
104
- * Only to be used for runtine messages.
105
- * @remarks - Serialization during submit happens via {@link serializeOpContents}
106
- * @param mutableMessage - op message received
107
- */
108
- export declare function ensureContentsDeserialized(mutableMessage: ISequencedDocumentMessage): void;
109
102
  /**
110
103
  * Unpacks runtime messages.
111
104
  *
@@ -1 +1 @@
1
- {"version":3,"file":"remoteMessageProcessor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAEN,yBAAyB,EACzB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAGN,KAAK,uCAAuC,EAC5C,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAkB,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAoB,MAAM,iBAAiB,CAAC;AAI/D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,yBAAyB,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAC7B;IACA,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,uCAAuC,EAAE,CAAC;IACpD,UAAU,EAAE,cAAc,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;CACrB,GACD;IACA,IAAI,EAAE,sBAAsB,CAAC;IAC7B,UAAU,EAAE,cAAc,CAAC;IAC3B,WAAW,EAAE,uCAAuC,CAAC;IACrD,MAAM,CAAC,EAAE,KAAK,CAAC;CACd,GACD;IACA,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,uCAAuC,CAAC;IACrD,MAAM,CAAC,EAAE,KAAK,CAAC;CACd,CAAC;AAWL;;;;;GAKG;AACH,qBAAa,sBAAsB;IAIjC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALnC,OAAO,CAAC,eAAe,CAAkB;gBAGvB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,EAC9B,iBAAiB,EAAE,iBAAiB;IAGtD,IAAW,eAAe,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE1D;IAEM,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAItD;;;;;;;;;;;;;;;;;;OAkBG;IACI,OAAO,CACb,iBAAiB,EAAE,yBAAyB,EAC5C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACvC,oBAAoB,GAAG,SAAS;IA0DnC;;;OAGG;IACH,OAAO,CAAC,6BAA6B;CAkDrC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,cAAc,EAAE,yBAAyB,GAAG,IAAI,CAM1F;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,yBAAyB,EAClC,aAAa,GAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAe,GAClD,OAAO,CAuBT"}
1
+ {"version":3,"file":"remoteMessageProcessor.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAEN,yBAAyB,EACzB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAGN,KAAK,uCAAuC,EAC5C,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAkB,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAoB,MAAM,iBAAiB,CAAC;AAC/D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,yBAAyB,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAC7B;IACA,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,uCAAuC,EAAE,CAAC;IACpD,UAAU,EAAE,cAAc,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;CACrB,GACD;IACA,IAAI,EAAE,sBAAsB,CAAC;IAC7B,UAAU,EAAE,cAAc,CAAC;IAC3B,WAAW,EAAE,uCAAuC,CAAC;IACrD,MAAM,CAAC,EAAE,KAAK,CAAC;CACd,GACD;IACA,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,uCAAuC,CAAC;IACrD,MAAM,CAAC,EAAE,KAAK,CAAC;CACd,CAAC;AAWL;;;;;GAKG;AACH,qBAAa,sBAAsB;IAIjC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALnC,OAAO,CAAC,eAAe,CAAkB;gBAGvB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,EAC9B,iBAAiB,EAAE,iBAAiB;IAGtD,IAAW,eAAe,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE1D;IAEM,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAItD;;;;;;;;;;;;;;;;;;OAkBG;IACI,OAAO,CACb,iBAAiB,EAAE,yBAAyB,EAC5C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACvC,oBAAoB,GAAG,SAAS;IA0DnC;;;OAGG;IACH,OAAO,CAAC,6BAA6B;CAkDrC;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,yBAAyB,EAClC,aAAa,GAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAe,GAClD,OAAO,CAuBT"}
@@ -145,19 +145,6 @@ export class RemoteMessageProcessor {
145
145
  };
146
146
  }
147
147
  }
148
- /**
149
- * Takes an incoming runtime message JSON.parse's its contents in place, if needed (old Loader does this for us).
150
- * Only to be used for runtine messages.
151
- * @remarks - Serialization during submit happens via {@link serializeOpContents}
152
- * @param mutableMessage - op message received
153
- */
154
- export function ensureContentsDeserialized(mutableMessage) {
155
- // This should become unconditional once Loader LTS reaches 2.4 or later.
156
- // There will be a long time of needing both cases, until LTS advances to that point.
157
- if (typeof mutableMessage.contents === "string" && mutableMessage.contents !== "") {
158
- mutableMessage.contents = JSON.parse(mutableMessage.contents);
159
- }
160
- }
161
148
  /**
162
149
  * For a given message, it moves the nested InboundContainerRuntimeMessage props one level up.
163
150
  *
@@ -1 +1 @@
1
- {"version":3,"file":"remoteMessageProcessor.js","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tMessageType,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\n\nimport {\n\tContainerMessageType,\n\ttype InboundContainerRuntimeMessage,\n\ttype InboundSequencedContainerRuntimeMessage,\n} from \"../messageTypes.js\";\nimport { asBatchMetadata } from \"../metadata.js\";\n\nimport { OpDecompressor } from \"./opDecompressor.js\";\nimport { OpGroupingManager, isGroupedBatch } from \"./opGroupingManager.js\";\nimport { OpSplitter, isChunkedMessage } from \"./opSplitter.js\";\n// eslint-disable-next-line unused-imports/no-unused-imports -- Used by \"@link\" comment annotation below\nimport { serializeOpContents } from \"./outbox.js\";\n\n/**\n * Info about the batch we learn when we process the first message\n */\nexport interface BatchStartInfo {\n\t/**\n\t * Batch ID, if present\n\t */\n\treadonly batchId: string | undefined;\n\t/**\n\t * clientId that sent this batch. Used to compute Batch ID if needed\n\t */\n\treadonly clientId: string;\n\t/**\n\t * Client Sequence Number of the Grouped Batch message, or the first message in the ungrouped batch.\n\t * Used to compute Batch ID if needed\n\t *\n\t * @remarks For chunked batches, this is the CSN of the \"representative\" chunk (the final chunk).\n\t * For grouped batches, clientSequenceNumber on messages is overwritten, so we track this original value here.\n\t */\n\treadonly batchStartCsn: number;\n\t/**\n\t * The first message in the batch, or if the batch is empty, the empty grouped batch message.\n\t * Used for accessing the sequence numbers for the (start of the) batch.\n\t *\n\t * @remarks Do not use clientSequenceNumber here, use batchStartCsn instead.\n\t */\n\treadonly keyMessage: ISequencedDocumentMessage;\n}\n\n/**\n * Result of processing the next inbound message.\n * Depending on the message and configuration of RemoteMessageProcessor, the result may be:\n * - A full batch of messages (including a single-message batch)\n * - The first message of a multi-message batch\n * - The next message in a multi-message batch\n */\nexport type InboundMessageResult =\n\t| {\n\t\t\ttype: \"fullBatch\";\n\t\t\tmessages: InboundSequencedContainerRuntimeMessage[];\n\t\t\tbatchStart: BatchStartInfo;\n\t\t\tlength: number;\n\t\t\tgroupedBatch: boolean; // Messages in a grouped batches are sent to the runtime in bunches.\n\t }\n\t| {\n\t\t\ttype: \"batchStartingMessage\";\n\t\t\tbatchStart: BatchStartInfo;\n\t\t\tnextMessage: InboundSequencedContainerRuntimeMessage;\n\t\t\tlength?: never;\n\t }\n\t| {\n\t\t\ttype: \"nextBatchMessage\";\n\t\t\tbatchEnd?: boolean;\n\t\t\tnextMessage: InboundSequencedContainerRuntimeMessage;\n\t\t\tlength?: never;\n\t };\n\nfunction assertHasClientId(\n\tmessage: ISequencedDocumentMessage,\n): asserts message is ISequencedDocumentMessage & { clientId: string } {\n\tassert(\n\t\tmessage.clientId !== null,\n\t\t0xa02 /* Server-generated message should not reach RemoteMessageProcessor */,\n\t);\n}\n\n/**\n * Stateful class for processing incoming remote messages as the virtualization measures are unwrapped,\n * potentially across numerous inbound ops.\n *\n * @internal\n */\nexport class RemoteMessageProcessor {\n\tprivate batchInProgress: boolean = false;\n\n\tconstructor(\n\t\tprivate readonly opSplitter: OpSplitter,\n\t\tprivate readonly opDecompressor: OpDecompressor,\n\t\tprivate readonly opGroupingManager: OpGroupingManager,\n\t) {}\n\n\tpublic get partialMessages(): ReadonlyMap<string, string[]> {\n\t\treturn this.opSplitter.chunks;\n\t}\n\n\tpublic clearPartialMessagesFor(clientId: string): void {\n\t\tthis.opSplitter.clearPartialChunks(clientId);\n\t}\n\n\t/**\n\t * Ungroups and Unchunks the runtime ops of a batch received over the wire\n\t * @param remoteMessageCopy - A shallow copy of a message from another client, possibly virtualized\n\t * (grouped, compressed, and/or chunked).\n\t * Being a shallow copy, it's considered mutable, meaning no other Container or other parallel procedure\n\t * depends on this object instance.\n\t * Note remoteMessageCopy.contents (and other object props) MUST not be modified,\n\t * but may be overwritten (as is the case with contents).\n\t *\n\t * Incoming messages will always have compression, chunking, and grouped batching happen in a defined order and that order cannot be changed.\n\t * When processing these messages, the order is:\n\t * 1. If chunked, process the chunk and only continue if this is a final chunk\n\t * 2. If compressed, decompress the message and store for further unrolling of the decompressed content\n\t * 3. If grouped, ungroup the message\n\t * For more details, see https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/container-runtime/src/opLifecycle/README.md#inbound\n\t *\n\t * @returns all the unchunked, decompressed, ungrouped, unpacked InboundSequencedContainerRuntimeMessage from a single batch\n\t * or undefined if the batch is not yet complete.\n\t */\n\tpublic process(\n\t\tremoteMessageCopy: ISequencedDocumentMessage,\n\t\tlogLegacyCase: (codePath: string) => void,\n\t): InboundMessageResult | undefined {\n\t\tlet message = remoteMessageCopy;\n\n\t\tassertHasClientId(message);\n\t\tconst clientId = message.clientId;\n\n\t\tif (isChunkedMessage(message)) {\n\t\t\tconst chunkProcessingResult = this.opSplitter.processChunk(message);\n\t\t\t// Only continue further if current chunk is the final chunk\n\t\t\tif (!chunkProcessingResult.isFinalChunk) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// This message will always be compressed\n\t\t\tmessage = chunkProcessingResult.message;\n\t\t}\n\n\t\tif (this.opDecompressor.isCompressedMessage(message)) {\n\t\t\tthis.opDecompressor.decompressAndStore(message);\n\t\t}\n\n\t\tif (this.opDecompressor.currentlyUnrolling) {\n\t\t\tmessage = this.opDecompressor.unroll(message);\n\t\t\t// Need to unpack after unrolling if not a groupedBatch\n\t\t\tif (!isGroupedBatch(message)) {\n\t\t\t\tunpack(message);\n\t\t\t}\n\t\t}\n\n\t\tif (isGroupedBatch(message)) {\n\t\t\t// We should be awaiting a new batch (batchInProgress false)\n\t\t\tassert(!this.batchInProgress, 0x9d3 /* Grouped batch interrupting another batch */);\n\t\t\tconst batchId = asBatchMetadata(message.metadata)?.batchId;\n\t\t\tconst groupedMessages = this.opGroupingManager\n\t\t\t\t.ungroupOp(message)\n\t\t\t\t.map((innerMessage) => unpack(innerMessage));\n\n\t\t\treturn {\n\t\t\t\ttype: \"fullBatch\",\n\t\t\t\tmessages: groupedMessages, // Will be [] for an empty batch\n\t\t\t\tbatchStart: {\n\t\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\t\tclientId,\n\t\t\t\t\tbatchId,\n\t\t\t\t\tkeyMessage: groupedMessages[0] ?? message, // For an empty batch, this is the empty grouped batch message. Needed for sequence numbers for this batch\n\t\t\t\t},\n\t\t\t\tlength: groupedMessages.length, // Will be 0 for an empty batch\n\t\t\t\tgroupedBatch: true,\n\t\t\t};\n\t\t}\n\n\t\t// Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked\n\t\tunpackRuntimeMessage(message, logLegacyCase);\n\n\t\treturn this.getResultBasedOnBatchMetadata(\n\t\t\tmessage as InboundSequencedContainerRuntimeMessage & { clientId: string },\n\t\t);\n\t}\n\n\t/**\n\t * Now that the message has been \"unwrapped\" as to any virtualization (grouping, compression, chunking),\n\t * inspect the batch metadata flag and determine what kind of result to return.\n\t */\n\tprivate getResultBasedOnBatchMetadata(\n\t\tmessage: InboundSequencedContainerRuntimeMessage & { clientId: string },\n\t): InboundMessageResult {\n\t\tconst batchMetadataFlag = asBatchMetadata(message.metadata)?.batch;\n\t\tif (!this.batchInProgress) {\n\t\t\t// We are waiting for a new batch\n\t\t\tassert(batchMetadataFlag !== false, 0x9d5 /* Unexpected batch end marker */);\n\n\t\t\t// Start of a new multi-message batch\n\t\t\tif (batchMetadataFlag === true) {\n\t\t\t\tthis.batchInProgress = true;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"batchStartingMessage\",\n\t\t\t\t\tbatchStart: {\n\t\t\t\t\t\tbatchId: asBatchMetadata(message.metadata)?.batchId,\n\t\t\t\t\t\tclientId: message.clientId,\n\t\t\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\t\t\tkeyMessage: message,\n\t\t\t\t\t},\n\t\t\t\t\tnextMessage: message,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Single-message batch (Since metadata flag is undefined)\n\t\t\treturn {\n\t\t\t\ttype: \"fullBatch\",\n\t\t\t\tmessages: [message],\n\t\t\t\tbatchStart: {\n\t\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\t\tclientId: message.clientId,\n\t\t\t\t\tbatchId: asBatchMetadata(message.metadata)?.batchId,\n\t\t\t\t\tkeyMessage: message,\n\t\t\t\t},\n\t\t\t\tlength: 1,\n\t\t\t\tgroupedBatch: false,\n\t\t\t};\n\t\t}\n\t\tassert(batchMetadataFlag !== true, 0x9d6 /* Unexpected batch start marker */);\n\n\t\t// Clear batchInProgress state if the batch is ending\n\t\tif (batchMetadataFlag === false) {\n\t\t\tthis.batchInProgress = false;\n\t\t}\n\n\t\treturn {\n\t\t\ttype: \"nextBatchMessage\",\n\t\t\tnextMessage: message,\n\t\t\tbatchEnd: batchMetadataFlag === false,\n\t\t};\n\t}\n}\n\n/**\n * Takes an incoming runtime message JSON.parse's its contents in place, if needed (old Loader does this for us).\n * Only to be used for runtine messages.\n * @remarks - Serialization during submit happens via {@link serializeOpContents}\n * @param mutableMessage - op message received\n */\nexport function ensureContentsDeserialized(mutableMessage: ISequencedDocumentMessage): void {\n\t// This should become unconditional once Loader LTS reaches 2.4 or later.\n\t// There will be a long time of needing both cases, until LTS advances to that point.\n\tif (typeof mutableMessage.contents === \"string\" && mutableMessage.contents !== \"\") {\n\t\tmutableMessage.contents = JSON.parse(mutableMessage.contents);\n\t}\n}\n\n/**\n * For a given message, it moves the nested InboundContainerRuntimeMessage props one level up.\n *\n * The return type illustrates the assumption that the message param\n * becomes a InboundSequencedContainerRuntimeMessage by the time the function returns\n * (but there is no runtime validation of the 'type').\n */\nfunction unpack(message: ISequencedDocumentMessage): InboundSequencedContainerRuntimeMessage {\n\t// We assume the contents is an InboundContainerRuntimeMessage (the message is \"packed\")\n\tconst contents = message.contents as InboundContainerRuntimeMessage;\n\n\t// We're going to unpack message in-place (promoting those properties of contents up to message itself)\n\tconst messageUnpacked = message as InboundSequencedContainerRuntimeMessage;\n\n\tmessageUnpacked.type = contents.type;\n\tmessageUnpacked.contents = contents.contents;\n\treturn messageUnpacked;\n}\n\n/**\n * Unpacks runtime messages.\n *\n * @remarks This API makes no promises regarding backward-compatibility. This is internal API.\n * @param message - message (as it observed in storage / service)\n * @returns whether the given message was unpacked\n *\n * @internal\n */\nexport function unpackRuntimeMessage(\n\tmessage: ISequencedDocumentMessage,\n\tlogLegacyCase: (codePath: string) => void = () => {},\n): boolean {\n\tif (message.type !== MessageType.Operation) {\n\t\t// Legacy format, but it's already \"unpacked\",\n\t\t// i.e. message.type is actually ContainerMessageType.\n\t\t// Or it's non-runtime message.\n\t\t// Nothing to do in such case.\n\t\treturn false;\n\t}\n\n\t// legacy op format?\n\t// TODO: Unsure if this is a real format we should be concerned with. There doesn't appear to be anything prepared to handle the address member.\n\tif (\n\t\t(message.contents as { address?: unknown }).address !== undefined &&\n\t\t(message.contents as { type?: unknown }).type === undefined\n\t) {\n\t\tmessage.type = ContainerMessageType.FluidDataStoreOp;\n\t\tlogLegacyCase(\"unpackRuntimeMessage_contentsWithAddress\");\n\t} else {\n\t\t// new format\n\t\tunpack(message);\n\t}\n\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"remoteMessageProcessor.js","sourceRoot":"","sources":["../../src/opLifecycle/remoteMessageProcessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAC7D,OAAO,EACN,WAAW,GAEX,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACN,oBAAoB,GAGpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAAqB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAc,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA0D/D,SAAS,iBAAiB,CACzB,OAAkC;IAElC,MAAM,CACL,OAAO,CAAC,QAAQ,KAAK,IAAI,EACzB,KAAK,CAAC,sEAAsE,CAC5E,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,sBAAsB;IAGlC,YACkB,UAAsB,EACtB,cAA8B,EAC9B,iBAAoC;QAFpC,eAAU,GAAV,UAAU,CAAY;QACtB,mBAAc,GAAd,cAAc,CAAgB;QAC9B,sBAAiB,GAAjB,iBAAiB,CAAmB;QAL9C,oBAAe,GAAY,KAAK,CAAC;IAMtC,CAAC;IAEJ,IAAW,eAAe;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAC/B,CAAC;IAEM,uBAAuB,CAAC,QAAgB;QAC9C,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACI,OAAO,CACb,iBAA4C,EAC5C,aAAyC;QAEzC,IAAI,OAAO,GAAG,iBAAiB,CAAC;QAEhC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAElC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,MAAM,qBAAqB,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YACpE,4DAA4D;YAC5D,IAAI,CAAC,qBAAqB,CAAC,YAAY,EAAE,CAAC;gBACzC,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,yCAAyC;YACzC,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC;QACzC,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,CAAC,kBAAkB,EAAE,CAAC;YAC5C,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9C,uDAAuD;YACvD,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,OAAO,CAAC,CAAC;YACjB,CAAC;QACF,CAAC;QAED,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,4DAA4D;YAC5D,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,8CAA8C,CAAC,CAAC;YACpF,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;YAC3D,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB;iBAC5C,SAAS,CAAC,OAAO,CAAC;iBAClB,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;YAE9C,OAAO;gBACN,IAAI,EAAE,WAAW;gBACjB,QAAQ,EAAE,eAAe,EAAE,gCAAgC;gBAC3D,UAAU,EAAE;oBACX,aAAa,EAAE,OAAO,CAAC,oBAAoB;oBAC3C,QAAQ;oBACR,OAAO;oBACP,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,0GAA0G;iBACrJ;gBACD,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,+BAA+B;gBAC/D,YAAY,EAAE,IAAI;aAClB,CAAC;QACH,CAAC;QAED,oGAAoG;QACpG,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QAE7C,OAAO,IAAI,CAAC,6BAA6B,CACxC,OAAyE,CACzE,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,6BAA6B,CACpC,OAAuE;QAEvE,MAAM,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;QACnE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAC3B,iCAAiC;YACjC,MAAM,CAAC,iBAAiB,KAAK,KAAK,EAAE,KAAK,CAAC,iCAAiC,CAAC,CAAC;YAE7E,qCAAqC;YACrC,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;gBAChC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;gBAC5B,OAAO;oBACN,IAAI,EAAE,sBAAsB;oBAC5B,UAAU,EAAE;wBACX,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO;wBACnD,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,aAAa,EAAE,OAAO,CAAC,oBAAoB;wBAC3C,UAAU,EAAE,OAAO;qBACnB;oBACD,WAAW,EAAE,OAAO;iBACpB,CAAC;YACH,CAAC;YAED,0DAA0D;YAC1D,OAAO;gBACN,IAAI,EAAE,WAAW;gBACjB,QAAQ,EAAE,CAAC,OAAO,CAAC;gBACnB,UAAU,EAAE;oBACX,aAAa,EAAE,OAAO,CAAC,oBAAoB;oBAC3C,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO;oBACnD,UAAU,EAAE,OAAO;iBACnB;gBACD,MAAM,EAAE,CAAC;gBACT,YAAY,EAAE,KAAK;aACnB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,iBAAiB,KAAK,IAAI,EAAE,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAE9E,qDAAqD;QACrD,IAAI,iBAAiB,KAAK,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC9B,CAAC;QAED,OAAO;YACN,IAAI,EAAE,kBAAkB;YACxB,WAAW,EAAE,OAAO;YACpB,QAAQ,EAAE,iBAAiB,KAAK,KAAK;SACrC,CAAC;IACH,CAAC;CACD;AAED;;;;;;GAMG;AACH,SAAS,MAAM,CAAC,OAAkC;IACjD,wFAAwF;IACxF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAA0C,CAAC;IAEpE,uGAAuG;IACvG,MAAM,eAAe,GAAG,OAAkD,CAAC;IAE3E,eAAe,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IACrC,eAAe,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;IAC7C,OAAO,eAAe,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CACnC,OAAkC,EAClC,gBAA4C,GAAG,EAAE,GAAE,CAAC;IAEpD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,SAAS,EAAE,CAAC;QAC5C,8CAA8C;QAC9C,sDAAsD;QACtD,+BAA+B;QAC/B,8BAA8B;QAC9B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,gJAAgJ;IAChJ,IACE,OAAO,CAAC,QAAkC,CAAC,OAAO,KAAK,SAAS;QAChE,OAAO,CAAC,QAA+B,CAAC,IAAI,KAAK,SAAS,EAC1D,CAAC;QACF,OAAO,CAAC,IAAI,GAAG,oBAAoB,CAAC,gBAAgB,CAAC;QACrD,aAAa,CAAC,0CAA0C,CAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACP,aAAa;QACb,MAAM,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tMessageType,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\n\nimport {\n\tContainerMessageType,\n\ttype InboundContainerRuntimeMessage,\n\ttype InboundSequencedContainerRuntimeMessage,\n} from \"../messageTypes.js\";\nimport { asBatchMetadata } from \"../metadata.js\";\n\nimport { OpDecompressor } from \"./opDecompressor.js\";\nimport { OpGroupingManager, isGroupedBatch } from \"./opGroupingManager.js\";\nimport { OpSplitter, isChunkedMessage } from \"./opSplitter.js\";\n/**\n * Info about the batch we learn when we process the first message\n */\nexport interface BatchStartInfo {\n\t/**\n\t * Batch ID, if present\n\t */\n\treadonly batchId: string | undefined;\n\t/**\n\t * clientId that sent this batch. Used to compute Batch ID if needed\n\t */\n\treadonly clientId: string;\n\t/**\n\t * Client Sequence Number of the Grouped Batch message, or the first message in the ungrouped batch.\n\t * Used to compute Batch ID if needed\n\t *\n\t * @remarks For chunked batches, this is the CSN of the \"representative\" chunk (the final chunk).\n\t * For grouped batches, clientSequenceNumber on messages is overwritten, so we track this original value here.\n\t */\n\treadonly batchStartCsn: number;\n\t/**\n\t * The first message in the batch, or if the batch is empty, the empty grouped batch message.\n\t * Used for accessing the sequence numbers for the (start of the) batch.\n\t *\n\t * @remarks Do not use clientSequenceNumber here, use batchStartCsn instead.\n\t */\n\treadonly keyMessage: ISequencedDocumentMessage;\n}\n\n/**\n * Result of processing the next inbound message.\n * Depending on the message and configuration of RemoteMessageProcessor, the result may be:\n * - A full batch of messages (including a single-message batch)\n * - The first message of a multi-message batch\n * - The next message in a multi-message batch\n */\nexport type InboundMessageResult =\n\t| {\n\t\t\ttype: \"fullBatch\";\n\t\t\tmessages: InboundSequencedContainerRuntimeMessage[];\n\t\t\tbatchStart: BatchStartInfo;\n\t\t\tlength: number;\n\t\t\tgroupedBatch: boolean; // Messages in a grouped batches are sent to the runtime in bunches.\n\t }\n\t| {\n\t\t\ttype: \"batchStartingMessage\";\n\t\t\tbatchStart: BatchStartInfo;\n\t\t\tnextMessage: InboundSequencedContainerRuntimeMessage;\n\t\t\tlength?: never;\n\t }\n\t| {\n\t\t\ttype: \"nextBatchMessage\";\n\t\t\tbatchEnd?: boolean;\n\t\t\tnextMessage: InboundSequencedContainerRuntimeMessage;\n\t\t\tlength?: never;\n\t };\n\nfunction assertHasClientId(\n\tmessage: ISequencedDocumentMessage,\n): asserts message is ISequencedDocumentMessage & { clientId: string } {\n\tassert(\n\t\tmessage.clientId !== null,\n\t\t0xa02 /* Server-generated message should not reach RemoteMessageProcessor */,\n\t);\n}\n\n/**\n * Stateful class for processing incoming remote messages as the virtualization measures are unwrapped,\n * potentially across numerous inbound ops.\n *\n * @internal\n */\nexport class RemoteMessageProcessor {\n\tprivate batchInProgress: boolean = false;\n\n\tconstructor(\n\t\tprivate readonly opSplitter: OpSplitter,\n\t\tprivate readonly opDecompressor: OpDecompressor,\n\t\tprivate readonly opGroupingManager: OpGroupingManager,\n\t) {}\n\n\tpublic get partialMessages(): ReadonlyMap<string, string[]> {\n\t\treturn this.opSplitter.chunks;\n\t}\n\n\tpublic clearPartialMessagesFor(clientId: string): void {\n\t\tthis.opSplitter.clearPartialChunks(clientId);\n\t}\n\n\t/**\n\t * Ungroups and Unchunks the runtime ops of a batch received over the wire\n\t * @param remoteMessageCopy - A shallow copy of a message from another client, possibly virtualized\n\t * (grouped, compressed, and/or chunked).\n\t * Being a shallow copy, it's considered mutable, meaning no other Container or other parallel procedure\n\t * depends on this object instance.\n\t * Note remoteMessageCopy.contents (and other object props) MUST not be modified,\n\t * but may be overwritten (as is the case with contents).\n\t *\n\t * Incoming messages will always have compression, chunking, and grouped batching happen in a defined order and that order cannot be changed.\n\t * When processing these messages, the order is:\n\t * 1. If chunked, process the chunk and only continue if this is a final chunk\n\t * 2. If compressed, decompress the message and store for further unrolling of the decompressed content\n\t * 3. If grouped, ungroup the message\n\t * For more details, see https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/container-runtime/src/opLifecycle/README.md#inbound\n\t *\n\t * @returns all the unchunked, decompressed, ungrouped, unpacked InboundSequencedContainerRuntimeMessage from a single batch\n\t * or undefined if the batch is not yet complete.\n\t */\n\tpublic process(\n\t\tremoteMessageCopy: ISequencedDocumentMessage,\n\t\tlogLegacyCase: (codePath: string) => void,\n\t): InboundMessageResult | undefined {\n\t\tlet message = remoteMessageCopy;\n\n\t\tassertHasClientId(message);\n\t\tconst clientId = message.clientId;\n\n\t\tif (isChunkedMessage(message)) {\n\t\t\tconst chunkProcessingResult = this.opSplitter.processChunk(message);\n\t\t\t// Only continue further if current chunk is the final chunk\n\t\t\tif (!chunkProcessingResult.isFinalChunk) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// This message will always be compressed\n\t\t\tmessage = chunkProcessingResult.message;\n\t\t}\n\n\t\tif (this.opDecompressor.isCompressedMessage(message)) {\n\t\t\tthis.opDecompressor.decompressAndStore(message);\n\t\t}\n\n\t\tif (this.opDecompressor.currentlyUnrolling) {\n\t\t\tmessage = this.opDecompressor.unroll(message);\n\t\t\t// Need to unpack after unrolling if not a groupedBatch\n\t\t\tif (!isGroupedBatch(message)) {\n\t\t\t\tunpack(message);\n\t\t\t}\n\t\t}\n\n\t\tif (isGroupedBatch(message)) {\n\t\t\t// We should be awaiting a new batch (batchInProgress false)\n\t\t\tassert(!this.batchInProgress, 0x9d3 /* Grouped batch interrupting another batch */);\n\t\t\tconst batchId = asBatchMetadata(message.metadata)?.batchId;\n\t\t\tconst groupedMessages = this.opGroupingManager\n\t\t\t\t.ungroupOp(message)\n\t\t\t\t.map((innerMessage) => unpack(innerMessage));\n\n\t\t\treturn {\n\t\t\t\ttype: \"fullBatch\",\n\t\t\t\tmessages: groupedMessages, // Will be [] for an empty batch\n\t\t\t\tbatchStart: {\n\t\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\t\tclientId,\n\t\t\t\t\tbatchId,\n\t\t\t\t\tkeyMessage: groupedMessages[0] ?? message, // For an empty batch, this is the empty grouped batch message. Needed for sequence numbers for this batch\n\t\t\t\t},\n\t\t\t\tlength: groupedMessages.length, // Will be 0 for an empty batch\n\t\t\t\tgroupedBatch: true,\n\t\t\t};\n\t\t}\n\n\t\t// Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked\n\t\tunpackRuntimeMessage(message, logLegacyCase);\n\n\t\treturn this.getResultBasedOnBatchMetadata(\n\t\t\tmessage as InboundSequencedContainerRuntimeMessage & { clientId: string },\n\t\t);\n\t}\n\n\t/**\n\t * Now that the message has been \"unwrapped\" as to any virtualization (grouping, compression, chunking),\n\t * inspect the batch metadata flag and determine what kind of result to return.\n\t */\n\tprivate getResultBasedOnBatchMetadata(\n\t\tmessage: InboundSequencedContainerRuntimeMessage & { clientId: string },\n\t): InboundMessageResult {\n\t\tconst batchMetadataFlag = asBatchMetadata(message.metadata)?.batch;\n\t\tif (!this.batchInProgress) {\n\t\t\t// We are waiting for a new batch\n\t\t\tassert(batchMetadataFlag !== false, 0x9d5 /* Unexpected batch end marker */);\n\n\t\t\t// Start of a new multi-message batch\n\t\t\tif (batchMetadataFlag === true) {\n\t\t\t\tthis.batchInProgress = true;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"batchStartingMessage\",\n\t\t\t\t\tbatchStart: {\n\t\t\t\t\t\tbatchId: asBatchMetadata(message.metadata)?.batchId,\n\t\t\t\t\t\tclientId: message.clientId,\n\t\t\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\t\t\tkeyMessage: message,\n\t\t\t\t\t},\n\t\t\t\t\tnextMessage: message,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Single-message batch (Since metadata flag is undefined)\n\t\t\treturn {\n\t\t\t\ttype: \"fullBatch\",\n\t\t\t\tmessages: [message],\n\t\t\t\tbatchStart: {\n\t\t\t\t\tbatchStartCsn: message.clientSequenceNumber,\n\t\t\t\t\tclientId: message.clientId,\n\t\t\t\t\tbatchId: asBatchMetadata(message.metadata)?.batchId,\n\t\t\t\t\tkeyMessage: message,\n\t\t\t\t},\n\t\t\t\tlength: 1,\n\t\t\t\tgroupedBatch: false,\n\t\t\t};\n\t\t}\n\t\tassert(batchMetadataFlag !== true, 0x9d6 /* Unexpected batch start marker */);\n\n\t\t// Clear batchInProgress state if the batch is ending\n\t\tif (batchMetadataFlag === false) {\n\t\t\tthis.batchInProgress = false;\n\t\t}\n\n\t\treturn {\n\t\t\ttype: \"nextBatchMessage\",\n\t\t\tnextMessage: message,\n\t\t\tbatchEnd: batchMetadataFlag === false,\n\t\t};\n\t}\n}\n\n/**\n * For a given message, it moves the nested InboundContainerRuntimeMessage props one level up.\n *\n * The return type illustrates the assumption that the message param\n * becomes a InboundSequencedContainerRuntimeMessage by the time the function returns\n * (but there is no runtime validation of the 'type').\n */\nfunction unpack(message: ISequencedDocumentMessage): InboundSequencedContainerRuntimeMessage {\n\t// We assume the contents is an InboundContainerRuntimeMessage (the message is \"packed\")\n\tconst contents = message.contents as InboundContainerRuntimeMessage;\n\n\t// We're going to unpack message in-place (promoting those properties of contents up to message itself)\n\tconst messageUnpacked = message as InboundSequencedContainerRuntimeMessage;\n\n\tmessageUnpacked.type = contents.type;\n\tmessageUnpacked.contents = contents.contents;\n\treturn messageUnpacked;\n}\n\n/**\n * Unpacks runtime messages.\n *\n * @remarks This API makes no promises regarding backward-compatibility. This is internal API.\n * @param message - message (as it observed in storage / service)\n * @returns whether the given message was unpacked\n *\n * @internal\n */\nexport function unpackRuntimeMessage(\n\tmessage: ISequencedDocumentMessage,\n\tlogLegacyCase: (codePath: string) => void = () => {},\n): boolean {\n\tif (message.type !== MessageType.Operation) {\n\t\t// Legacy format, but it's already \"unpacked\",\n\t\t// i.e. message.type is actually ContainerMessageType.\n\t\t// Or it's non-runtime message.\n\t\t// Nothing to do in such case.\n\t\treturn false;\n\t}\n\n\t// legacy op format?\n\t// TODO: Unsure if this is a real format we should be concerned with. There doesn't appear to be anything prepared to handle the address member.\n\tif (\n\t\t(message.contents as { address?: unknown }).address !== undefined &&\n\t\t(message.contents as { type?: unknown }).type === undefined\n\t) {\n\t\tmessage.type = ContainerMessageType.FluidDataStoreOp;\n\t\tlogLegacyCase(\"unpackRuntimeMessage_contentsWithAddress\");\n\t} else {\n\t\t// new format\n\t\tunpack(message);\n\t}\n\n\treturn true;\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/container-runtime";
8
- export declare const pkgVersion = "2.31.0";
8
+ export declare const pkgVersion = "2.32.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-runtime";
8
- export const pkgVersion = "2.31.0";
8
+ export const pkgVersion = "2.32.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.31.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.32.0\";\n"]}
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { IDisposable, type ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
6
6
  import { type InboundSequencedContainerRuntimeMessage } from "./messageTypes.js";
7
- import { BatchId, BatchMessage, InboundMessageResult } from "./opLifecycle/index.js";
7
+ import { BatchId, LocalBatchMessage, InboundMessageResult } from "./opLifecycle/index.js";
8
8
  /**
9
9
  * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the
10
10
  * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.
@@ -123,7 +123,7 @@ export declare class PendingStateManager implements IDisposable {
123
123
  * or undefined if the batch was not yet sent (e.g. by the time we flushed we lost the connection)
124
124
  * @param ignoreBatchId - Whether to ignore the batchId in the batchStartInfo
125
125
  */
126
- onFlushBatch(batch: BatchMessage[], clientSequenceNumber: number | undefined, ignoreBatchId?: boolean): void;
126
+ onFlushBatch(batch: LocalBatchMessage[], clientSequenceNumber: number | undefined, ignoreBatchId?: boolean): void;
127
127
  /**
128
128
  * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted
129
129
  * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.
@@ -1 +1 @@
1
- {"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAYzF,OAAO,EAEN,KAAK,uCAAuC,EAE5C,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACN,OAAO,EACP,YAAY,EAGZ,oBAAoB,EACpB,MAAM,wBAAwB,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,uBAAuB,EAAE,MAAM,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,SAAS,EAAE;QACV;;;WAGG;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB;;;WAGG;QACH,aAAa,EAAE,MAAM,CAAC;QACtB;;WAEG;QACH,MAAM,EAAE,MAAM,CAAC;QACf;;WAEG;QACH,aAAa,CAAC,EAAE,OAAO,CAAC;KACxB,CAAC;CACF;AAgBD,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,aAAa,EAAE,eAAe,EAAE,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC5C,eAAe,EACf,SAAS,GAAG,iBAAiB,GAAG,YAAY,CAC5C,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACpC,SAAS,IAAI,OAAO,CAAC;IACrB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAAC;IAC/B,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,aAAa,CAAC,KAAK,EAAE,0BAA0B,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3E,kBAAkB,EAAE,MAAM,OAAO,CAAC;IAClC,UAAU,EAAE,MAAM,OAAO,CAAC;CAC1B;AA4DD;;;GAGG;AACH,wBAAgB,4BAA4B,CAC3C,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACP,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAOjD;AASD;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IAqFrD,OAAO,CAAC,QAAQ,CAAC,YAAY;IApF9B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyC;IAEzE;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAyB;IAGzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAGzB;IAEH;;OAEG;IACH,OAAO,CAAC,sBAAsB,CAAqB;IAEnD;;;OAGG;IACH,IAAW,oBAAoB,IAAI,MAAM,CAExC;IAED;;;;OAIG;IACH,IAAW,mCAAmC,IAAI,MAAM,GAAG,SAAS,CAEnE;IAED;;;OAGG;IACI,kBAAkB,IAAI,OAAO;IAI7B,aAAa,CAAC,sBAAsB,CAAC,EAAE,MAAM,GAAG,kBAAkB;IA+BzE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,YAAY,EAAE,oBAAoB,EACnD,iBAAiB,EAAE,kBAAkB,GAAG,SAAS,EACjD,MAAM,EAAE,oBAAoB;IAQ7B,IAAW,QAAQ,IAAI,OAAO,CAE7B;IACD,SAAgB,OAAO,QAAO,IAAI,CAA2B;IAE7D;;;;;;;OAOG;IACI,YAAY,CAClB,KAAK,EAAE,YAAY,EAAE,EACrB,oBAAoB,EAAE,MAAM,GAAG,SAAS,EACxC,aAAa,CAAC,EAAE,OAAO,GACrB,IAAI;IAmCP;;;OAGG;IACU,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0C9D;;;;;OAKG;IACH,OAAO,CAAC,8BAA8B;IAuBtC;;;;;;;;;;OAUG;IACI,sBAAsB,CAC5B,OAAO,EAAE,oBAAoB,EAC7B,KAAK,EAAE,OAAO,GACZ;QACF,OAAO,EAAE,uCAAuC,CAAC;QACjD,eAAe,CAAC,EAAE,OAAO,CAAC;KAC1B,EAAE;IAoBH;;;;;;OAMG;IACH,OAAO,CAAC,2BAA2B;IA4BnC;;;;;;OAMG;IACH,OAAO,CAAC,yBAAyB;IAwEjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsDzB;;;;OAIG;IACI,mBAAmB,IAAI,IAAI;CA6GlC"}
1
+ {"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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"}
@@ -171,7 +171,7 @@ export class PendingStateManager {
171
171
  : [uuid(), -1]; // -1 will indicate not a real clientId/CSN pair
172
172
  assert(clientId !== undefined, 0xa33 /* clientId (from stateHandler) could only be undefined if we've never connected, but we have a CSN so we know that's not the case */);
173
173
  for (const message of batch) {
174
- const { contents: content = "", referenceSequenceNumber, localOpMetadata, metadata: opMetadata, } = message;
174
+ const { serializedOp: content, referenceSequenceNumber, localOpMetadata, metadata: opMetadata, } = message;
175
175
  const pendingMessage = {
176
176
  type: "message",
177
177
  referenceSequenceNumber,
@@ -1 +1 @@
1
- {"version":3,"file":"pendingStateManager.js","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable, type ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tDataProcessingError,\n\tLoggingError,\n\textractSafePropertiesFromMessage,\n\tcreateChildLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport Deque from \"double-ended-queue\";\nimport { v4 as uuid } from \"uuid\";\n\nimport {\n\ttype InboundContainerRuntimeMessage,\n\ttype InboundSequencedContainerRuntimeMessage,\n\ttype LocalContainerRuntimeMessage,\n} from \"./messageTypes.js\";\nimport { asBatchMetadata, asEmptyBatchLocalOpMetadata } from \"./metadata.js\";\nimport {\n\tBatchId,\n\tBatchMessage,\n\tgetEffectiveBatchId,\n\tBatchStartInfo,\n\tInboundMessageResult,\n} from \"./opLifecycle/index.js\";\n\n/**\n * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the\n * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.\n *\n * @remarks This is the current serialization format for pending local state when a Container is serialized.\n */\nexport interface IPendingMessage {\n\ttype: \"message\";\n\treferenceSequenceNumber: number;\n\tcontent: string;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n\tsequenceNumber?: number;\n\t/**\n\t * Info about the batch this pending message belongs to, for validation and for computing the batchId on reconnect\n\t * We don't include batchId itself to avoid redundancy, because that's stamped on opMetadata above\n\t */\n\tbatchInfo: {\n\t\t/**\n\t\t * The Batch's original clientId, from when it was first flushed to be submitted.\n\t\t * Or, a random uuid if it was never submitted (and batchStartCsn will be -1)\n\t\t */\n\t\tclientId: string;\n\t\t/**\n\t\t * The Batch's original clientSequenceNumber, from when it was first flushed to be submitted\n\t\t * Or, -1 if it was never submitted (and clientId will be a random uuid)\n\t\t */\n\t\tbatchStartCsn: number;\n\t\t/**\n\t\t * length of the batch (how many runtime messages here)\n\t\t */\n\t\tlength: number;\n\t\t/**\n\t\t * If true, don't compare batchID of incoming batches to this. e.g. ID Allocation Batch IDs should be ignored\n\t\t */\n\t\tignoreBatchId?: boolean;\n\t};\n}\n\ntype Patch<T, U> = U & Omit<T, keyof U>;\n\n/**\n * First version of the type (pre-dates batchInfo)\n */\ntype IPendingMessageV0 = Patch<IPendingMessage, { batchInfo?: undefined }>;\n\n/**\n * Union of all supported schemas for when applying stashed ops\n *\n * @remarks When the format changes, this type should update to reflect all possible schemas.\n */\ntype IPendingMessageFromStash = IPendingMessageV0 | IPendingMessage;\n\nexport interface IPendingLocalState {\n\t/**\n\t * list of pending states, including ops and batch information\n\t */\n\tpendingStates: IPendingMessage[];\n}\n\n/**\n * Info needed to replay/resubmit a pending message\n */\nexport type PendingMessageResubmitData = Pick<\n\tIPendingMessage,\n\t\"content\" | \"localOpMetadata\" | \"opMetadata\"\n>;\n\nexport interface IRuntimeStateHandler {\n\tconnected(): boolean;\n\tclientId(): string | undefined;\n\tapplyStashedOp(content: string): Promise<unknown>;\n\treSubmitBatch(batch: PendingMessageResubmitData[], batchId: BatchId): void;\n\tisActiveConnection: () => boolean;\n\tisAttached: () => boolean;\n}\n\nfunction isEmptyBatchPendingMessage(message: IPendingMessageFromStash): boolean {\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst content = JSON.parse(message.content);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\treturn content.type === \"groupedBatch\" && content.contents?.length === 0;\n}\n\nfunction buildPendingMessageContent(message: InboundSequencedContainerRuntimeMessage): string {\n\t// IMPORTANT: Order matters here, this must match the order of the properties used\n\t// when submitting the message.\n\tconst { type, contents }: InboundContainerRuntimeMessage = message;\n\t// Any properties that are not defined, won't be emitted by stringify.\n\treturn JSON.stringify({ type, contents });\n}\n\nfunction typesOfKeys<T extends object>(obj: T): Record<keyof T, string> {\n\treturn Object.keys(obj).reduce((acc, key) => {\n\t\tacc[key] = typeof obj[key];\n\t\treturn acc;\n\t}, {}) as Record<keyof T, string>;\n}\n\nfunction scrubAndStringify(\n\tmessage: InboundContainerRuntimeMessage | LocalContainerRuntimeMessage,\n): string {\n\t// Scrub the whole object in case there are unexpected keys\n\tconst scrubbed: Record<string, unknown> = typesOfKeys(message);\n\n\t// For these known/expected keys, we can either drill into the object (for contents)\n\t// or just use the value as-is (since it's not personal info)\n\tscrubbed.contents = message.contents && typesOfKeys(message.contents);\n\tscrubbed.type = message.type;\n\n\treturn JSON.stringify(scrubbed);\n}\n\n/**\n * Finds and returns the index where the strings diverge, and the character at that index in each string (or undefined if not applicable)\n */\nfunction findFirstRawCharacterMismatched(\n\ta: string,\n\tb: string,\n): [index: number, charA?: string, charB?: string] {\n\tconst minLength = Math.min(a.length, b.length);\n\tfor (let i = 0; i < minLength; i++) {\n\t\tif (a[i] !== b[i]) {\n\t\t\treturn [i, a[i], b[i]];\n\t\t}\n\t}\n\n\t// Since we didn't return in the loop, the shorter string must be a prefix of the other.\n\t// If they're the same length, return -1 to indicate they're identical.\n\t// Otherwise, the next character of the longer one is where they differ. No need to return that next character.\n\treturn a.length === b.length\n\t\t? [-1, undefined, undefined]\n\t\t: [minLength, a[minLength], b[minLength]];\n}\n\n/**\n * Finds and returns the index where the strings diverge, and the character at that index in each string (or undefined if not applicable)\n * It scrubs non-ASCII characters since they convey more meaning (privacy consideration)\n */\nexport function findFirstCharacterMismatched(\n\ta: string,\n\tb: string,\n): [index: number, charA?: string, charB?: string] {\n\tconst [index, rawCharA, rawCharB] = findFirstRawCharacterMismatched(a, b);\n\n\tconst charA = (rawCharA?.codePointAt(0) ?? 0) <= 0x7f ? rawCharA : \"[non-ASCII]\";\n\tconst charB = (rawCharB?.codePointAt(0) ?? 0) <= 0x7f ? rawCharB : \"[non-ASCII]\";\n\n\treturn [index, charA, charB];\n}\n\nfunction withoutLocalOpMetadata(message: IPendingMessage): IPendingMessage {\n\treturn {\n\t\t...message,\n\t\tlocalOpMetadata: undefined,\n\t};\n}\n\n/**\n * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been\n * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed\n * batches along with the messages.\n * When the Container reconnects, it replays the pending states, which includes manual flushing\n * of messages and triggering resubmission of unacked ops.\n *\n * It verifies that all the ops are acked, are received in the right order and batch information is correct.\n */\nexport class PendingStateManager implements IDisposable {\n\t/**\n\t * Messages that will need to be resubmitted if not ack'd before the next reconnection\n\t */\n\tprivate readonly pendingMessages = new Deque<IPendingMessage>();\n\t/**\n\t * Messages stashed from a previous container, now being rehydrated. Need to be resubmitted.\n\t */\n\tprivate readonly initialMessages = new Deque<IPendingMessageFromStash>();\n\n\t/**\n\t * Sequenced local ops that are saved when stashing since pending ops may depend on them\n\t */\n\tprivate savedOps: IPendingMessage[] = [];\n\n\t// eslint-disable-next-line unicorn/consistent-function-scoping -- Property is defined once; no need to extract inner lambda\n\tprivate readonly disposeOnce = new Lazy<void>(() => {\n\t\tthis.initialMessages.clear();\n\t\tthis.pendingMessages.clear();\n\t});\n\n\t/**\n\t * Used to ensure we don't replay ops on the same connection twice\n\t */\n\tprivate clientIdFromLastReplay: string | undefined;\n\n\t/**\n\t * The pending messages count. Includes `pendingMessages` and `initialMessages` to keep in sync with\n\t * 'hasPendingMessages'.\n\t */\n\tpublic get pendingMessagesCount(): number {\n\t\treturn this.pendingMessages.length + this.initialMessages.length;\n\t}\n\n\t/**\n\t * The minimumPendingMessageSequenceNumber is the minimum of the first pending message and the first initial message.\n\t *\n\t * We need this so that we can properly keep local data and maintain the correct sequence window.\n\t */\n\tpublic get minimumPendingMessageSequenceNumber(): number | undefined {\n\t\treturn this.pendingMessages.peekFront()?.referenceSequenceNumber;\n\t}\n\n\t/**\n\t * Called to check if there are any pending messages in the pending message queue.\n\t * @returns A boolean indicating whether there are messages or not.\n\t */\n\tpublic hasPendingMessages(): boolean {\n\t\treturn this.pendingMessagesCount !== 0;\n\t}\n\n\tpublic getLocalState(snapshotSequenceNumber?: number): IPendingLocalState {\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x2e9 /* \"Must call getLocalState() after applying initial states\" */,\n\t\t);\n\t\t// Using snapshot sequence number to filter ops older than our latest snapshot.\n\t\t// Such ops should not be declared in pending/stashed state. Snapshot seq num will not\n\t\t// be available when the container is not attached. Therefore, no filtering is needed.\n\t\tconst newSavedOps = [...this.savedOps].filter((message) => {\n\t\t\tassert(\n\t\t\t\tmessage.sequenceNumber !== undefined,\n\t\t\t\t0x97c /* saved op should already have a sequence number */,\n\t\t\t);\n\t\t\treturn message.sequenceNumber > (snapshotSequenceNumber ?? 0);\n\t\t});\n\t\tfor (const message of this.pendingMessages.toArray()) {\n\t\t\tif (\n\t\t\t\tsnapshotSequenceNumber !== undefined &&\n\t\t\t\tmessage.referenceSequenceNumber < snapshotSequenceNumber\n\t\t\t) {\n\t\t\t\tthrow new LoggingError(\"trying to stash ops older than our latest snapshot\");\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tpendingStates: [\n\t\t\t\t...newSavedOps,\n\t\t\t\t...this.pendingMessages.toArray().map((message) => withoutLocalOpMetadata(message)),\n\t\t\t],\n\t\t};\n\t}\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tprivate readonly stateHandler: IRuntimeStateHandler,\n\t\tstashedLocalState: IPendingLocalState | undefined,\n\t\tlogger: ITelemetryBaseLogger,\n\t) {\n\t\tthis.logger = createChildLogger({ logger });\n\t\tif (stashedLocalState?.pendingStates) {\n\t\t\tthis.initialMessages.push(...stashedLocalState.pendingStates);\n\t\t}\n\t}\n\n\tpublic get disposed(): boolean {\n\t\treturn this.disposeOnce.evaluated;\n\t}\n\tpublic readonly dispose = (): void => this.disposeOnce.value;\n\n\t/**\n\t * The given batch has been flushed, and needs to be tracked locally until the corresponding\n\t * acks are processed, to ensure it is successfully sent.\n\t * @param batch - The batch that was flushed\n\t * @param clientSequenceNumber - The CSN of the first message in the batch,\n\t * or undefined if the batch was not yet sent (e.g. by the time we flushed we lost the connection)\n\t * @param ignoreBatchId - Whether to ignore the batchId in the batchStartInfo\n\t */\n\tpublic onFlushBatch(\n\t\tbatch: BatchMessage[],\n\t\tclientSequenceNumber: number | undefined,\n\t\tignoreBatchId?: boolean,\n\t): void {\n\t\t// clientId and batchStartCsn are used for generating the batchId so we can detect container forks\n\t\t// where this batch was submitted by two different clients rehydrating from the same local state.\n\t\t// In the typical case where the batch was actually sent, use the clientId and clientSequenceNumber.\n\t\t// In the case where the batch was not sent, use a random uuid for clientId, and -1 for clientSequenceNumber to indicate this case.\n\t\t// This will guarantee uniqueness of the batchId, and is a suitable fallback since clientId/CSN is only needed if the batch was actually sent/sequenced.\n\t\tconst batchWasSent = clientSequenceNumber !== undefined;\n\t\tconst [clientId, batchStartCsn] = batchWasSent\n\t\t\t? [this.stateHandler.clientId(), clientSequenceNumber]\n\t\t\t: [uuid(), -1]; // -1 will indicate not a real clientId/CSN pair\n\t\tassert(\n\t\t\tclientId !== undefined,\n\t\t\t0xa33 /* clientId (from stateHandler) could only be undefined if we've never connected, but we have a CSN so we know that's not the case */,\n\t\t);\n\n\t\tfor (const message of batch) {\n\t\t\tconst {\n\t\t\t\tcontents: content = \"\",\n\t\t\t\treferenceSequenceNumber,\n\t\t\t\tlocalOpMetadata,\n\t\t\t\tmetadata: opMetadata,\n\t\t\t} = message;\n\t\t\tconst pendingMessage: IPendingMessage = {\n\t\t\t\ttype: \"message\",\n\t\t\t\treferenceSequenceNumber,\n\t\t\t\tcontent,\n\t\t\t\tlocalOpMetadata,\n\t\t\t\topMetadata,\n\t\t\t\t// Note: We only will read this off the first message, but put it on all for simplicity\n\t\t\t\tbatchInfo: { clientId, batchStartCsn, length: batch.length, ignoreBatchId },\n\t\t\t};\n\t\t\tthis.pendingMessages.push(pendingMessage);\n\t\t}\n\t}\n\n\t/**\n\t * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted\n\t * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.\n\t */\n\tpublic async applyStashedOpsAt(seqNum?: number): Promise<void> {\n\t\t// apply stashed ops at sequence number\n\t\twhile (!this.initialMessages.isEmpty()) {\n\t\t\tif (seqNum !== undefined) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst peekMessage = this.initialMessages.peekFront()!;\n\t\t\t\tif (peekMessage.referenceSequenceNumber > seqNum) {\n\t\t\t\t\tbreak; // nothing left to do at this sequence number\n\t\t\t\t}\n\t\t\t\tif (peekMessage.referenceSequenceNumber < seqNum) {\n\t\t\t\t\tthrow new Error(\"loaded from snapshot too recent to apply stashed ops\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst nextMessage = this.initialMessages.shift()!;\n\t\t\t// Nothing to apply if the message is an empty batch.\n\t\t\t// We still need to track it for resubmission.\n\t\t\ttry {\n\t\t\t\tif (isEmptyBatchPendingMessage(nextMessage)) {\n\t\t\t\t\tnextMessage.localOpMetadata = { emptyBatch: true }; // equivalent to applyStashedOp for empty batch\n\t\t\t\t\tpatchbatchInfo(nextMessage); // Back compat\n\t\t\t\t\tthis.pendingMessages.push(nextMessage);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it\n\t\t\t\tconst localOpMetadata = await this.stateHandler.applyStashedOp(nextMessage.content);\n\t\t\t\tif (this.stateHandler.isAttached()) {\n\t\t\t\t\tnextMessage.localOpMetadata = localOpMetadata;\n\t\t\t\t\t// then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect\n\t\t\t\t\tpatchbatchInfo(nextMessage); // Back compat\n\t\t\t\t\tthis.pendingMessages.push(nextMessage);\n\t\t\t\t} else {\n\t\t\t\t\tif (localOpMetadata !== undefined) {\n\t\t\t\t\t\tthrow new Error(\"Local Op Metadata must be undefined when not attached\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrow DataProcessingError.wrapIfUnrecognized(error, \"applyStashedOp\", nextMessage);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Compares the batch ID of the incoming batch with the pending batch ID for this client.\n\t * They should not match, as that would indicate a forked container.\n\t * @param remoteBatchStart - BatchStartInfo for an incoming batch *NOT* submitted by this client\n\t * @returns whether the batch IDs match\n\t */\n\tprivate remoteBatchMatchesPendingBatch(remoteBatchStart: BatchStartInfo): boolean {\n\t\t// Find the first pending message that uses Batch ID, to compare to the incoming remote batch.\n\t\t// If there is no such message, then the incoming remote batch doesn't have a match here and we can return.\n\t\tconst firstIndexUsingBatchId = Array.from({\n\t\t\tlength: this.pendingMessages.length,\n\t\t}).findIndex((_, i) => this.pendingMessages.get(i)?.batchInfo.ignoreBatchId !== true);\n\t\tconst pendingMessageUsingBatchId =\n\t\t\tfirstIndexUsingBatchId === -1\n\t\t\t\t? undefined\n\t\t\t\t: this.pendingMessages.get(firstIndexUsingBatchId);\n\n\t\tif (pendingMessageUsingBatchId === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We must compare the effective batch IDs, since one of these ops\n\t\t// may have been the original, not resubmitted, so wouldn't have its batch ID stamped yet.\n\t\tconst pendingBatchId = getEffectiveBatchId(pendingMessageUsingBatchId);\n\t\tconst inboundBatchId = getEffectiveBatchId(remoteBatchStart);\n\n\t\treturn pendingBatchId === inboundBatchId;\n\t}\n\n\t/**\n\t * Processes an inbound message or batch of messages - May be local or remote.\n\t *\n\t * @param inbound - The inbound message(s) to process, with extra info (e.g. about the start of a batch). Could be local or remote.\n\t * @param local - true if we submitted these messages and expect corresponding pending messages\n\t * @returns The inbound messages with localOpMetadata \"zipped\" in.\n\t *\n\t * @throws a DataProcessingError in either of these cases:\n\t * - The pending message content doesn't match the incoming message content for any message here\n\t * - The batch IDs *do match* but it's not local (indicates Container forking).\n\t */\n\tpublic processInboundMessages(\n\t\tinbound: InboundMessageResult,\n\t\tlocal: boolean,\n\t): {\n\t\tmessage: InboundSequencedContainerRuntimeMessage;\n\t\tlocalOpMetadata?: unknown;\n\t}[] {\n\t\tif (local) {\n\t\t\treturn this.processPendingLocalMessages(inbound);\n\t\t}\n\n\t\t// An inbound remote batch should not match the pending batch ID for this client.\n\t\t// That would indicate the container forked (two instances trying to submit the same local state)\n\t\tif (\"batchStart\" in inbound && this.remoteBatchMatchesPendingBatch(inbound.batchStart)) {\n\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\"Forked Container Error! Matching batchIds but mismatched clientId\",\n\t\t\t\t\"PendingStateManager.processInboundMessages\",\n\t\t\t\tinbound.batchStart.keyMessage,\n\t\t\t);\n\t\t}\n\n\t\t// No localOpMetadata for remote messages\n\t\tconst messages = inbound.type === \"fullBatch\" ? inbound.messages : [inbound.nextMessage];\n\t\treturn messages.map((message) => ({ message }));\n\t}\n\n\t/**\n\t * Processes the incoming message(s) from the server that were submitted by this client.\n\t * It verifies that messages are received in the right order and that any batch information is correct.\n\t * @param inbound - The inbound message(s) (originating from this client) to correlate with the pending local state\n\t * @throws DataProcessingError if the pending message content doesn't match the incoming message content for any message here\n\t * @returns The inbound messages with localOpMetadata \"zipped\" in.\n\t */\n\tprivate processPendingLocalMessages(inbound: InboundMessageResult): {\n\t\tmessage: InboundSequencedContainerRuntimeMessage;\n\t\tlocalOpMetadata: unknown;\n\t}[] {\n\t\tif (\"batchStart\" in inbound) {\n\t\t\tthis.onLocalBatchBegin(inbound.batchStart, inbound.length);\n\t\t}\n\n\t\t// Empty batch\n\t\tif (inbound.length === 0) {\n\t\t\tconst localOpMetadata = this.processNextPendingMessage(\n\t\t\t\tinbound.batchStart.keyMessage.sequenceNumber,\n\t\t\t);\n\t\t\tassert(\n\t\t\t\tasEmptyBatchLocalOpMetadata(localOpMetadata)?.emptyBatch === true,\n\t\t\t\t0xa20 /* Expected empty batch marker */,\n\t\t\t);\n\t\t\treturn [];\n\t\t}\n\n\t\tconst messages = inbound.type === \"fullBatch\" ? inbound.messages : [inbound.nextMessage];\n\n\t\treturn messages.map((message) => ({\n\t\t\tmessage,\n\t\t\tlocalOpMetadata: this.processNextPendingMessage(message.sequenceNumber, message),\n\t\t}));\n\t}\n\n\t/**\n\t * Processes the pending local copy of message that's been ack'd by the server.\n\t * @param sequenceNumber - The sequenceNumber from the server corresponding to the next pending message.\n\t * @param message - [optional] The entire incoming message, for comparing contents with the pending message for extra validation.\n\t * @throws DataProcessingError if the pending message content doesn't match the incoming message content.\n\t * @returns - The localOpMetadata of the next pending message, to be sent to whoever submitted the original message.\n\t */\n\tprivate processNextPendingMessage(\n\t\tsequenceNumber: number,\n\t\tmessage?: InboundSequencedContainerRuntimeMessage,\n\t): unknown {\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0x169 /* \"No pending message found for this remote message\" */,\n\t\t);\n\n\t\tpendingMessage.sequenceNumber = sequenceNumber;\n\t\tthis.savedOps.push(withoutLocalOpMetadata(pendingMessage));\n\n\t\tthis.pendingMessages.shift();\n\n\t\t// message is undefined in the Empty Batch case,\n\t\t// because we don't have an incoming message to compare and pendingMessage is just a placeholder anyway.\n\t\tif (message !== undefined) {\n\t\t\tconst messageContent = buildPendingMessageContent(message);\n\n\t\t\t// Stringified content should match\n\t\t\t// If it doesn't, collect as much info about the difference as possible (privacy-wise) and log it\n\t\t\tif (pendingMessage.content !== messageContent) {\n\t\t\t\tconst [pendingLength, incomingLength] = [\n\t\t\t\t\tpendingMessage.content.length,\n\t\t\t\t\tmessageContent.length,\n\t\t\t\t];\n\t\t\t\tconst [mismatchStartIndex, pendingChar, incomingChar] = findFirstCharacterMismatched(\n\t\t\t\t\tpendingMessage.content,\n\t\t\t\t\tmessageContent,\n\t\t\t\t);\n\n\t\t\t\tconst pendingContentObj = JSON.parse(\n\t\t\t\t\tpendingMessage.content,\n\t\t\t\t) as LocalContainerRuntimeMessage;\n\t\t\t\tconst incomingContentObj = JSON.parse(\n\t\t\t\t\tmessageContent,\n\t\t\t\t) as InboundContainerRuntimeMessage;\n\n\t\t\t\t// Compare inner contents object, since that both should be { type, contents }\n\t\t\t\tconst contentsMatch =\n\t\t\t\t\tpendingContentObj.contents === incomingContentObj.contents ||\n\t\t\t\t\t(pendingContentObj.contents !== undefined &&\n\t\t\t\t\t\tincomingContentObj.contents !== undefined &&\n\t\t\t\t\t\tJSON.stringify(pendingContentObj.contents) ===\n\t\t\t\t\t\t\tJSON.stringify(incomingContentObj.contents));\n\n\t\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\t\teventName: \"unexpectedAckReceived\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tpendingContentScrubbed: scrubAndStringify(pendingContentObj),\n\t\t\t\t\t\tincomingContentScrubbed: scrubAndStringify(incomingContentObj),\n\t\t\t\t\t\tcontentsMatch,\n\t\t\t\t\t\tpendingLength,\n\t\t\t\t\t\tincomingLength,\n\t\t\t\t\t\tmismatchStartIndex,\n\t\t\t\t\t\tpendingChar,\n\t\t\t\t\t\tincomingChar,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t\"pending local message content mismatch\",\n\t\t\t\t\t\"unexpectedAckReceived\",\n\t\t\t\t\tmessage,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn pendingMessage.localOpMetadata;\n\t}\n\n\t/**\n\t * Check if the incoming batch matches the batch info for the next pending message.\n\t */\n\tprivate onLocalBatchBegin(batchStart: BatchStartInfo, batchLength?: number): void {\n\t\t// Get the next message from the pending queue. Verify a message exists.\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0xa21 /* No pending message found as we start processing this remote batch */,\n\t\t);\n\n\t\t// If this batch became empty on resubmit, batch.messages will be empty (but keyMessage is always set)\n\t\t// and the next pending message should be an empty batch marker.\n\t\t// More Info: We must submit empty batches and track them in case a different fork\n\t\t// of this container also submitted the same batch (and it may not be empty for that fork).\n\t\tconst firstMessage = batchStart.keyMessage;\n\t\t// -1 length is for back compat, undefined length means we actually don't know it\n\t\tconst skipLengthCheck =\n\t\t\tpendingMessage.batchInfo.length === -1 || batchLength === undefined;\n\t\tconst expectedPendingBatchLength =\n\t\t\tbatchLength === 0\n\t\t\t\t? 1 // For an empty batch, expect a singleton array with the empty batch marker\n\t\t\t\t: batchLength; // Otherwise, the lengths should actually match\n\n\t\t// Note: We don't need to use getEffectiveBatchId here, just check the explicit stamped batchID\n\t\t// That logic is needed only when comparing across potential container forks.\n\t\t// Furthermore, we also are comparing the batch IDs constituent data - clientId (it's local) and batchStartCsn.\n\t\tconst pendingBatchId = asBatchMetadata(pendingMessage.opMetadata)?.batchId;\n\t\tconst inboundBatchId = batchStart.batchId;\n\n\t\t// We expect the incoming batch to be of the same length, starting at the same clientSequenceNumber,\n\t\t// as the batch we originally submitted. The batchIds should match as well, if set (or neither should be set)\n\t\t// We have another later check to compare the message contents, which we'd expect to fail if this check does,\n\t\t// so we don't throw here, merely log. In a later release this check may replace that one since it's cheaper.\n\t\tif (\n\t\t\tpendingMessage.batchInfo.batchStartCsn !== batchStart.batchStartCsn ||\n\t\t\t(!skipLengthCheck && pendingMessage.batchInfo.length !== expectedPendingBatchLength) ||\n\t\t\tpendingBatchId !== inboundBatchId\n\t\t) {\n\t\t\tthis.logger?.sendErrorEvent({\n\t\t\t\teventName: \"BatchInfoMismatch\",\n\t\t\t\tdetails: {\n\t\t\t\t\tpendingBatchCsn: pendingMessage.batchInfo.batchStartCsn,\n\t\t\t\t\tbatchStartCsn: batchStart.batchStartCsn,\n\t\t\t\t\tpendingBatchLength: pendingMessage.batchInfo.length,\n\t\t\t\t\texpectedPendingBatchLength,\n\t\t\t\t\tbatchLength,\n\t\t\t\t\tpendingBatchId,\n\t\t\t\t\tinboundBatchId,\n\t\t\t\t\tpendingMessageBatchMetadata: asBatchMetadata(pendingMessage.opMetadata)?.batch,\n\t\t\t\t\tmessageBatchMetadata: asBatchMetadata(firstMessage?.metadata)?.batch,\n\t\t\t\t},\n\t\t\t\tmessageDetails: firstMessage && extractSafePropertiesFromMessage(firstMessage),\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending\n\t * states in its queue. This includes triggering resubmission of unacked ops.\n\t * ! Note: successfully resubmitting an op that has been successfully sequenced is not possible due to checks in the ConnectionStateHandler (Loader layer)\n\t */\n\tpublic replayPendingStates(): void {\n\t\tassert(\n\t\t\tthis.stateHandler.connected(),\n\t\t\t0x172 /* \"The connection state is not consistent with the runtime\" */,\n\t\t);\n\n\t\t// This assert suggests we are about to send same ops twice, which will result in data loss.\n\t\tassert(\n\t\t\tthis.clientIdFromLastReplay !== this.stateHandler.clientId(),\n\t\t\t0x173 /* \"replayPendingStates called twice for same clientId!\" */,\n\t\t);\n\t\tthis.clientIdFromLastReplay = this.stateHandler.clientId();\n\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x174 /* \"initial states should be empty before replaying pending\" */,\n\t\t);\n\n\t\tconst initialPendingMessagesCount = this.pendingMessages.length;\n\t\tlet remainingPendingMessagesCount = this.pendingMessages.length;\n\n\t\t// Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were\n\t\t// pending when we connected. This is important because the `reSubmitFn` might add more items in the queue\n\t\t// which must not be replayed.\n\t\twhile (remainingPendingMessagesCount > 0) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tlet pendingMessage = this.pendingMessages.shift()!;\n\t\t\tremainingPendingMessagesCount--;\n\n\t\t\tconst batchMetadataFlag = asBatchMetadata(pendingMessage.opMetadata)?.batch;\n\t\t\tassert(batchMetadataFlag !== false, 0x41b /* We cannot process batches in chunks */);\n\n\t\t\t// The next message starts a batch (possibly single-message), and we'll need its batchId.\n\t\t\tconst batchId = getEffectiveBatchId(pendingMessage);\n\n\t\t\tif (asEmptyBatchLocalOpMetadata(pendingMessage.localOpMetadata)?.emptyBatch === true) {\n\t\t\t\t// Resubmit no messages, with the batchId. Will result in another empty batch marker.\n\t\t\t\tthis.stateHandler.reSubmitBatch([], batchId);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * We must preserve the distinct batches on resubmit.\n\t\t\t * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will\n\t\t\t * either receive the whole batch ack or nothing at all. See {@link InboundBatchAggregator} for how this works.\n\t\t\t */\n\t\t\tif (batchMetadataFlag === undefined) {\n\t\t\t\t// Single-message batch\n\n\t\t\t\tthis.stateHandler.reSubmitBatch(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tbatchId,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// else: batchMetadataFlag === true (It's a typical multi-message batch)\n\n\t\t\tassert(\n\t\t\t\tremainingPendingMessagesCount > 0,\n\t\t\t\t0x554 /* Last pending message cannot be a batch begin */,\n\t\t\t);\n\n\t\t\tconst batch: PendingMessageResubmitData[] = [];\n\n\t\t\t// check is >= because batch end may be last pending message\n\t\t\twhile (remainingPendingMessagesCount >= 0) {\n\t\t\t\tbatch.push({\n\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t});\n\n\t\t\t\tif (pendingMessage.opMetadata?.batch === false) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tassert(remainingPendingMessagesCount > 0, 0x555 /* No batch end found */);\n\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tpendingMessage = this.pendingMessages.shift()!;\n\t\t\t\tremainingPendingMessagesCount--;\n\t\t\t\tassert(\n\t\t\t\t\tpendingMessage.opMetadata?.batch !== true,\n\t\t\t\t\t0x556 /* Batch start needs a corresponding batch end */,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.stateHandler.reSubmitBatch(batch, batchId);\n\t\t}\n\n\t\t// pending ops should no longer depend on previous sequenced local ops after resubmit\n\t\tthis.savedOps = [];\n\n\t\t// We replayPendingStates on read connections too - we expect these to get nack'd though, and to then reconnect\n\t\t// on a write connection and replay again. This filters out the replay that happens on the read connection so\n\t\t// we only see the replays on write connections (that have a chance to go through).\n\t\tif (this.stateHandler.isActiveConnection()) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"PendingStatesReplayed\",\n\t\t\t\tcount: initialPendingMessagesCount,\n\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * For back-compat if trying to apply stashed ops that pre-date batchInfo\n */\nfunction patchbatchInfo(\n\tmessage: IPendingMessageFromStash,\n): asserts message is IPendingMessage {\n\tconst batchInfo: IPendingMessageFromStash[\"batchInfo\"] = message.batchInfo;\n\tif (batchInfo === undefined) {\n\t\t// Using uuid guarantees uniqueness, retaining existing behavior\n\t\tmessage.batchInfo = { clientId: uuid(), batchStartCsn: -1, length: -1 };\n\t}\n}\n"]}
1
+ {"version":3,"file":"pendingStateManager.js","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable, type ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tDataProcessingError,\n\tLoggingError,\n\textractSafePropertiesFromMessage,\n\tcreateChildLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport Deque from \"double-ended-queue\";\nimport { v4 as uuid } from \"uuid\";\n\nimport {\n\ttype InboundContainerRuntimeMessage,\n\ttype InboundSequencedContainerRuntimeMessage,\n\ttype LocalContainerRuntimeMessage,\n} from \"./messageTypes.js\";\nimport { asBatchMetadata, asEmptyBatchLocalOpMetadata } from \"./metadata.js\";\nimport {\n\tBatchId,\n\tLocalBatchMessage,\n\tgetEffectiveBatchId,\n\tBatchStartInfo,\n\tInboundMessageResult,\n} from \"./opLifecycle/index.js\";\n\n/**\n * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the\n * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.\n *\n * @remarks This is the current serialization format for pending local state when a Container is serialized.\n */\nexport interface IPendingMessage {\n\ttype: \"message\";\n\treferenceSequenceNumber: number;\n\tcontent: string;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n\tsequenceNumber?: number;\n\t/**\n\t * Info about the batch this pending message belongs to, for validation and for computing the batchId on reconnect\n\t * We don't include batchId itself to avoid redundancy, because that's stamped on opMetadata above\n\t */\n\tbatchInfo: {\n\t\t/**\n\t\t * The Batch's original clientId, from when it was first flushed to be submitted.\n\t\t * Or, a random uuid if it was never submitted (and batchStartCsn will be -1)\n\t\t */\n\t\tclientId: string;\n\t\t/**\n\t\t * The Batch's original clientSequenceNumber, from when it was first flushed to be submitted\n\t\t * Or, -1 if it was never submitted (and clientId will be a random uuid)\n\t\t */\n\t\tbatchStartCsn: number;\n\t\t/**\n\t\t * length of the batch (how many runtime messages here)\n\t\t */\n\t\tlength: number;\n\t\t/**\n\t\t * If true, don't compare batchID of incoming batches to this. e.g. ID Allocation Batch IDs should be ignored\n\t\t */\n\t\tignoreBatchId?: boolean;\n\t};\n}\n\ntype Patch<T, U> = U & Omit<T, keyof U>;\n\n/**\n * First version of the type (pre-dates batchInfo)\n */\ntype IPendingMessageV0 = Patch<IPendingMessage, { batchInfo?: undefined }>;\n\n/**\n * Union of all supported schemas for when applying stashed ops\n *\n * @remarks When the format changes, this type should update to reflect all possible schemas.\n */\ntype IPendingMessageFromStash = IPendingMessageV0 | IPendingMessage;\n\nexport interface IPendingLocalState {\n\t/**\n\t * list of pending states, including ops and batch information\n\t */\n\tpendingStates: IPendingMessage[];\n}\n\n/**\n * Info needed to replay/resubmit a pending message\n */\nexport type PendingMessageResubmitData = Pick<\n\tIPendingMessage,\n\t\"content\" | \"localOpMetadata\" | \"opMetadata\"\n>;\n\nexport interface IRuntimeStateHandler {\n\tconnected(): boolean;\n\tclientId(): string | undefined;\n\tapplyStashedOp(content: string): Promise<unknown>;\n\treSubmitBatch(batch: PendingMessageResubmitData[], batchId: BatchId): void;\n\tisActiveConnection: () => boolean;\n\tisAttached: () => boolean;\n}\n\nfunction isEmptyBatchPendingMessage(message: IPendingMessageFromStash): boolean {\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst content = JSON.parse(message.content);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\treturn content.type === \"groupedBatch\" && content.contents?.length === 0;\n}\n\nfunction buildPendingMessageContent(message: InboundSequencedContainerRuntimeMessage): string {\n\t// IMPORTANT: Order matters here, this must match the order of the properties used\n\t// when submitting the message.\n\tconst { type, contents }: InboundContainerRuntimeMessage = message;\n\t// Any properties that are not defined, won't be emitted by stringify.\n\treturn JSON.stringify({ type, contents });\n}\n\nfunction typesOfKeys<T extends object>(obj: T): Record<keyof T, string> {\n\treturn Object.keys(obj).reduce((acc, key) => {\n\t\tacc[key] = typeof obj[key];\n\t\treturn acc;\n\t}, {}) as Record<keyof T, string>;\n}\n\nfunction scrubAndStringify(\n\tmessage: InboundContainerRuntimeMessage | LocalContainerRuntimeMessage,\n): string {\n\t// Scrub the whole object in case there are unexpected keys\n\tconst scrubbed: Record<string, unknown> = typesOfKeys(message);\n\n\t// For these known/expected keys, we can either drill into the object (for contents)\n\t// or just use the value as-is (since it's not personal info)\n\tscrubbed.contents = message.contents && typesOfKeys(message.contents);\n\tscrubbed.type = message.type;\n\n\treturn JSON.stringify(scrubbed);\n}\n\n/**\n * Finds and returns the index where the strings diverge, and the character at that index in each string (or undefined if not applicable)\n */\nfunction findFirstRawCharacterMismatched(\n\ta: string,\n\tb: string,\n): [index: number, charA?: string, charB?: string] {\n\tconst minLength = Math.min(a.length, b.length);\n\tfor (let i = 0; i < minLength; i++) {\n\t\tif (a[i] !== b[i]) {\n\t\t\treturn [i, a[i], b[i]];\n\t\t}\n\t}\n\n\t// Since we didn't return in the loop, the shorter string must be a prefix of the other.\n\t// If they're the same length, return -1 to indicate they're identical.\n\t// Otherwise, the next character of the longer one is where they differ. No need to return that next character.\n\treturn a.length === b.length\n\t\t? [-1, undefined, undefined]\n\t\t: [minLength, a[minLength], b[minLength]];\n}\n\n/**\n * Finds and returns the index where the strings diverge, and the character at that index in each string (or undefined if not applicable)\n * It scrubs non-ASCII characters since they convey more meaning (privacy consideration)\n */\nexport function findFirstCharacterMismatched(\n\ta: string,\n\tb: string,\n): [index: number, charA?: string, charB?: string] {\n\tconst [index, rawCharA, rawCharB] = findFirstRawCharacterMismatched(a, b);\n\n\tconst charA = (rawCharA?.codePointAt(0) ?? 0) <= 0x7f ? rawCharA : \"[non-ASCII]\";\n\tconst charB = (rawCharB?.codePointAt(0) ?? 0) <= 0x7f ? rawCharB : \"[non-ASCII]\";\n\n\treturn [index, charA, charB];\n}\n\nfunction withoutLocalOpMetadata(message: IPendingMessage): IPendingMessage {\n\treturn {\n\t\t...message,\n\t\tlocalOpMetadata: undefined,\n\t};\n}\n\n/**\n * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been\n * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed\n * batches along with the messages.\n * When the Container reconnects, it replays the pending states, which includes manual flushing\n * of messages and triggering resubmission of unacked ops.\n *\n * It verifies that all the ops are acked, are received in the right order and batch information is correct.\n */\nexport class PendingStateManager implements IDisposable {\n\t/**\n\t * Messages that will need to be resubmitted if not ack'd before the next reconnection\n\t */\n\tprivate readonly pendingMessages = new Deque<IPendingMessage>();\n\t/**\n\t * Messages stashed from a previous container, now being rehydrated. Need to be resubmitted.\n\t */\n\tprivate readonly initialMessages = new Deque<IPendingMessageFromStash>();\n\n\t/**\n\t * Sequenced local ops that are saved when stashing since pending ops may depend on them\n\t */\n\tprivate savedOps: IPendingMessage[] = [];\n\n\t// eslint-disable-next-line unicorn/consistent-function-scoping -- Property is defined once; no need to extract inner lambda\n\tprivate readonly disposeOnce = new Lazy<void>(() => {\n\t\tthis.initialMessages.clear();\n\t\tthis.pendingMessages.clear();\n\t});\n\n\t/**\n\t * Used to ensure we don't replay ops on the same connection twice\n\t */\n\tprivate clientIdFromLastReplay: string | undefined;\n\n\t/**\n\t * The pending messages count. Includes `pendingMessages` and `initialMessages` to keep in sync with\n\t * 'hasPendingMessages'.\n\t */\n\tpublic get pendingMessagesCount(): number {\n\t\treturn this.pendingMessages.length + this.initialMessages.length;\n\t}\n\n\t/**\n\t * The minimumPendingMessageSequenceNumber is the minimum of the first pending message and the first initial message.\n\t *\n\t * We need this so that we can properly keep local data and maintain the correct sequence window.\n\t */\n\tpublic get minimumPendingMessageSequenceNumber(): number | undefined {\n\t\treturn this.pendingMessages.peekFront()?.referenceSequenceNumber;\n\t}\n\n\t/**\n\t * Called to check if there are any pending messages in the pending message queue.\n\t * @returns A boolean indicating whether there are messages or not.\n\t */\n\tpublic hasPendingMessages(): boolean {\n\t\treturn this.pendingMessagesCount !== 0;\n\t}\n\n\tpublic getLocalState(snapshotSequenceNumber?: number): IPendingLocalState {\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x2e9 /* \"Must call getLocalState() after applying initial states\" */,\n\t\t);\n\t\t// Using snapshot sequence number to filter ops older than our latest snapshot.\n\t\t// Such ops should not be declared in pending/stashed state. Snapshot seq num will not\n\t\t// be available when the container is not attached. Therefore, no filtering is needed.\n\t\tconst newSavedOps = [...this.savedOps].filter((message) => {\n\t\t\tassert(\n\t\t\t\tmessage.sequenceNumber !== undefined,\n\t\t\t\t0x97c /* saved op should already have a sequence number */,\n\t\t\t);\n\t\t\treturn message.sequenceNumber > (snapshotSequenceNumber ?? 0);\n\t\t});\n\t\tfor (const message of this.pendingMessages.toArray()) {\n\t\t\tif (\n\t\t\t\tsnapshotSequenceNumber !== undefined &&\n\t\t\t\tmessage.referenceSequenceNumber < snapshotSequenceNumber\n\t\t\t) {\n\t\t\t\tthrow new LoggingError(\"trying to stash ops older than our latest snapshot\");\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tpendingStates: [\n\t\t\t\t...newSavedOps,\n\t\t\t\t...this.pendingMessages.toArray().map((message) => withoutLocalOpMetadata(message)),\n\t\t\t],\n\t\t};\n\t}\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tprivate readonly stateHandler: IRuntimeStateHandler,\n\t\tstashedLocalState: IPendingLocalState | undefined,\n\t\tlogger: ITelemetryBaseLogger,\n\t) {\n\t\tthis.logger = createChildLogger({ logger });\n\t\tif (stashedLocalState?.pendingStates) {\n\t\t\tthis.initialMessages.push(...stashedLocalState.pendingStates);\n\t\t}\n\t}\n\n\tpublic get disposed(): boolean {\n\t\treturn this.disposeOnce.evaluated;\n\t}\n\tpublic readonly dispose = (): void => this.disposeOnce.value;\n\n\t/**\n\t * The given batch has been flushed, and needs to be tracked locally until the corresponding\n\t * acks are processed, to ensure it is successfully sent.\n\t * @param batch - The batch that was flushed\n\t * @param clientSequenceNumber - The CSN of the first message in the batch,\n\t * or undefined if the batch was not yet sent (e.g. by the time we flushed we lost the connection)\n\t * @param ignoreBatchId - Whether to ignore the batchId in the batchStartInfo\n\t */\n\tpublic onFlushBatch(\n\t\tbatch: LocalBatchMessage[],\n\t\tclientSequenceNumber: number | undefined,\n\t\tignoreBatchId?: boolean,\n\t): void {\n\t\t// clientId and batchStartCsn are used for generating the batchId so we can detect container forks\n\t\t// where this batch was submitted by two different clients rehydrating from the same local state.\n\t\t// In the typical case where the batch was actually sent, use the clientId and clientSequenceNumber.\n\t\t// In the case where the batch was not sent, use a random uuid for clientId, and -1 for clientSequenceNumber to indicate this case.\n\t\t// This will guarantee uniqueness of the batchId, and is a suitable fallback since clientId/CSN is only needed if the batch was actually sent/sequenced.\n\t\tconst batchWasSent = clientSequenceNumber !== undefined;\n\t\tconst [clientId, batchStartCsn] = batchWasSent\n\t\t\t? [this.stateHandler.clientId(), clientSequenceNumber]\n\t\t\t: [uuid(), -1]; // -1 will indicate not a real clientId/CSN pair\n\t\tassert(\n\t\t\tclientId !== undefined,\n\t\t\t0xa33 /* clientId (from stateHandler) could only be undefined if we've never connected, but we have a CSN so we know that's not the case */,\n\t\t);\n\n\t\tfor (const message of batch) {\n\t\t\tconst {\n\t\t\t\tserializedOp: content,\n\t\t\t\treferenceSequenceNumber,\n\t\t\t\tlocalOpMetadata,\n\t\t\t\tmetadata: opMetadata,\n\t\t\t} = message;\n\t\t\tconst pendingMessage: IPendingMessage = {\n\t\t\t\ttype: \"message\",\n\t\t\t\treferenceSequenceNumber,\n\t\t\t\tcontent,\n\t\t\t\tlocalOpMetadata,\n\t\t\t\topMetadata,\n\t\t\t\t// Note: We only will read this off the first message, but put it on all for simplicity\n\t\t\t\tbatchInfo: { clientId, batchStartCsn, length: batch.length, ignoreBatchId },\n\t\t\t};\n\t\t\tthis.pendingMessages.push(pendingMessage);\n\t\t}\n\t}\n\n\t/**\n\t * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted\n\t * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.\n\t */\n\tpublic async applyStashedOpsAt(seqNum?: number): Promise<void> {\n\t\t// apply stashed ops at sequence number\n\t\twhile (!this.initialMessages.isEmpty()) {\n\t\t\tif (seqNum !== undefined) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst peekMessage = this.initialMessages.peekFront()!;\n\t\t\t\tif (peekMessage.referenceSequenceNumber > seqNum) {\n\t\t\t\t\tbreak; // nothing left to do at this sequence number\n\t\t\t\t}\n\t\t\t\tif (peekMessage.referenceSequenceNumber < seqNum) {\n\t\t\t\t\tthrow new Error(\"loaded from snapshot too recent to apply stashed ops\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst nextMessage = this.initialMessages.shift()!;\n\t\t\t// Nothing to apply if the message is an empty batch.\n\t\t\t// We still need to track it for resubmission.\n\t\t\ttry {\n\t\t\t\tif (isEmptyBatchPendingMessage(nextMessage)) {\n\t\t\t\t\tnextMessage.localOpMetadata = { emptyBatch: true }; // equivalent to applyStashedOp for empty batch\n\t\t\t\t\tpatchbatchInfo(nextMessage); // Back compat\n\t\t\t\t\tthis.pendingMessages.push(nextMessage);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it\n\t\t\t\tconst localOpMetadata = await this.stateHandler.applyStashedOp(nextMessage.content);\n\t\t\t\tif (this.stateHandler.isAttached()) {\n\t\t\t\t\tnextMessage.localOpMetadata = localOpMetadata;\n\t\t\t\t\t// then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect\n\t\t\t\t\tpatchbatchInfo(nextMessage); // Back compat\n\t\t\t\t\tthis.pendingMessages.push(nextMessage);\n\t\t\t\t} else {\n\t\t\t\t\tif (localOpMetadata !== undefined) {\n\t\t\t\t\t\tthrow new Error(\"Local Op Metadata must be undefined when not attached\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrow DataProcessingError.wrapIfUnrecognized(error, \"applyStashedOp\", nextMessage);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Compares the batch ID of the incoming batch with the pending batch ID for this client.\n\t * They should not match, as that would indicate a forked container.\n\t * @param remoteBatchStart - BatchStartInfo for an incoming batch *NOT* submitted by this client\n\t * @returns whether the batch IDs match\n\t */\n\tprivate remoteBatchMatchesPendingBatch(remoteBatchStart: BatchStartInfo): boolean {\n\t\t// Find the first pending message that uses Batch ID, to compare to the incoming remote batch.\n\t\t// If there is no such message, then the incoming remote batch doesn't have a match here and we can return.\n\t\tconst firstIndexUsingBatchId = Array.from({\n\t\t\tlength: this.pendingMessages.length,\n\t\t}).findIndex((_, i) => this.pendingMessages.get(i)?.batchInfo.ignoreBatchId !== true);\n\t\tconst pendingMessageUsingBatchId =\n\t\t\tfirstIndexUsingBatchId === -1\n\t\t\t\t? undefined\n\t\t\t\t: this.pendingMessages.get(firstIndexUsingBatchId);\n\n\t\tif (pendingMessageUsingBatchId === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We must compare the effective batch IDs, since one of these ops\n\t\t// may have been the original, not resubmitted, so wouldn't have its batch ID stamped yet.\n\t\tconst pendingBatchId = getEffectiveBatchId(pendingMessageUsingBatchId);\n\t\tconst inboundBatchId = getEffectiveBatchId(remoteBatchStart);\n\n\t\treturn pendingBatchId === inboundBatchId;\n\t}\n\n\t/**\n\t * Processes an inbound message or batch of messages - May be local or remote.\n\t *\n\t * @param inbound - The inbound message(s) to process, with extra info (e.g. about the start of a batch). Could be local or remote.\n\t * @param local - true if we submitted these messages and expect corresponding pending messages\n\t * @returns The inbound messages with localOpMetadata \"zipped\" in.\n\t *\n\t * @throws a DataProcessingError in either of these cases:\n\t * - The pending message content doesn't match the incoming message content for any message here\n\t * - The batch IDs *do match* but it's not local (indicates Container forking).\n\t */\n\tpublic processInboundMessages(\n\t\tinbound: InboundMessageResult,\n\t\tlocal: boolean,\n\t): {\n\t\tmessage: InboundSequencedContainerRuntimeMessage;\n\t\tlocalOpMetadata?: unknown;\n\t}[] {\n\t\tif (local) {\n\t\t\treturn this.processPendingLocalMessages(inbound);\n\t\t}\n\n\t\t// An inbound remote batch should not match the pending batch ID for this client.\n\t\t// That would indicate the container forked (two instances trying to submit the same local state)\n\t\tif (\"batchStart\" in inbound && this.remoteBatchMatchesPendingBatch(inbound.batchStart)) {\n\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\"Forked Container Error! Matching batchIds but mismatched clientId\",\n\t\t\t\t\"PendingStateManager.processInboundMessages\",\n\t\t\t\tinbound.batchStart.keyMessage,\n\t\t\t);\n\t\t}\n\n\t\t// No localOpMetadata for remote messages\n\t\tconst messages = inbound.type === \"fullBatch\" ? inbound.messages : [inbound.nextMessage];\n\t\treturn messages.map((message) => ({ message }));\n\t}\n\n\t/**\n\t * Processes the incoming message(s) from the server that were submitted by this client.\n\t * It verifies that messages are received in the right order and that any batch information is correct.\n\t * @param inbound - The inbound message(s) (originating from this client) to correlate with the pending local state\n\t * @throws DataProcessingError if the pending message content doesn't match the incoming message content for any message here\n\t * @returns The inbound messages with localOpMetadata \"zipped\" in.\n\t */\n\tprivate processPendingLocalMessages(inbound: InboundMessageResult): {\n\t\tmessage: InboundSequencedContainerRuntimeMessage;\n\t\tlocalOpMetadata: unknown;\n\t}[] {\n\t\tif (\"batchStart\" in inbound) {\n\t\t\tthis.onLocalBatchBegin(inbound.batchStart, inbound.length);\n\t\t}\n\n\t\t// Empty batch\n\t\tif (inbound.length === 0) {\n\t\t\tconst localOpMetadata = this.processNextPendingMessage(\n\t\t\t\tinbound.batchStart.keyMessage.sequenceNumber,\n\t\t\t);\n\t\t\tassert(\n\t\t\t\tasEmptyBatchLocalOpMetadata(localOpMetadata)?.emptyBatch === true,\n\t\t\t\t0xa20 /* Expected empty batch marker */,\n\t\t\t);\n\t\t\treturn [];\n\t\t}\n\n\t\tconst messages = inbound.type === \"fullBatch\" ? inbound.messages : [inbound.nextMessage];\n\n\t\treturn messages.map((message) => ({\n\t\t\tmessage,\n\t\t\tlocalOpMetadata: this.processNextPendingMessage(message.sequenceNumber, message),\n\t\t}));\n\t}\n\n\t/**\n\t * Processes the pending local copy of message that's been ack'd by the server.\n\t * @param sequenceNumber - The sequenceNumber from the server corresponding to the next pending message.\n\t * @param message - [optional] The entire incoming message, for comparing contents with the pending message for extra validation.\n\t * @throws DataProcessingError if the pending message content doesn't match the incoming message content.\n\t * @returns - The localOpMetadata of the next pending message, to be sent to whoever submitted the original message.\n\t */\n\tprivate processNextPendingMessage(\n\t\tsequenceNumber: number,\n\t\tmessage?: InboundSequencedContainerRuntimeMessage,\n\t): unknown {\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0x169 /* \"No pending message found for this remote message\" */,\n\t\t);\n\n\t\tpendingMessage.sequenceNumber = sequenceNumber;\n\t\tthis.savedOps.push(withoutLocalOpMetadata(pendingMessage));\n\n\t\tthis.pendingMessages.shift();\n\n\t\t// message is undefined in the Empty Batch case,\n\t\t// because we don't have an incoming message to compare and pendingMessage is just a placeholder anyway.\n\t\tif (message !== undefined) {\n\t\t\tconst messageContent = buildPendingMessageContent(message);\n\n\t\t\t// Stringified content should match\n\t\t\t// If it doesn't, collect as much info about the difference as possible (privacy-wise) and log it\n\t\t\tif (pendingMessage.content !== messageContent) {\n\t\t\t\tconst [pendingLength, incomingLength] = [\n\t\t\t\t\tpendingMessage.content.length,\n\t\t\t\t\tmessageContent.length,\n\t\t\t\t];\n\t\t\t\tconst [mismatchStartIndex, pendingChar, incomingChar] = findFirstCharacterMismatched(\n\t\t\t\t\tpendingMessage.content,\n\t\t\t\t\tmessageContent,\n\t\t\t\t);\n\n\t\t\t\tconst pendingContentObj = JSON.parse(\n\t\t\t\t\tpendingMessage.content,\n\t\t\t\t) as LocalContainerRuntimeMessage;\n\t\t\t\tconst incomingContentObj = JSON.parse(\n\t\t\t\t\tmessageContent,\n\t\t\t\t) as InboundContainerRuntimeMessage;\n\n\t\t\t\t// Compare inner contents object, since that both should be { type, contents }\n\t\t\t\tconst contentsMatch =\n\t\t\t\t\tpendingContentObj.contents === incomingContentObj.contents ||\n\t\t\t\t\t(pendingContentObj.contents !== undefined &&\n\t\t\t\t\t\tincomingContentObj.contents !== undefined &&\n\t\t\t\t\t\tJSON.stringify(pendingContentObj.contents) ===\n\t\t\t\t\t\t\tJSON.stringify(incomingContentObj.contents));\n\n\t\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\t\teventName: \"unexpectedAckReceived\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tpendingContentScrubbed: scrubAndStringify(pendingContentObj),\n\t\t\t\t\t\tincomingContentScrubbed: scrubAndStringify(incomingContentObj),\n\t\t\t\t\t\tcontentsMatch,\n\t\t\t\t\t\tpendingLength,\n\t\t\t\t\t\tincomingLength,\n\t\t\t\t\t\tmismatchStartIndex,\n\t\t\t\t\t\tpendingChar,\n\t\t\t\t\t\tincomingChar,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t\"pending local message content mismatch\",\n\t\t\t\t\t\"unexpectedAckReceived\",\n\t\t\t\t\tmessage,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn pendingMessage.localOpMetadata;\n\t}\n\n\t/**\n\t * Check if the incoming batch matches the batch info for the next pending message.\n\t */\n\tprivate onLocalBatchBegin(batchStart: BatchStartInfo, batchLength?: number): void {\n\t\t// Get the next message from the pending queue. Verify a message exists.\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0xa21 /* No pending message found as we start processing this remote batch */,\n\t\t);\n\n\t\t// If this batch became empty on resubmit, batch.messages will be empty (but keyMessage is always set)\n\t\t// and the next pending message should be an empty batch marker.\n\t\t// More Info: We must submit empty batches and track them in case a different fork\n\t\t// of this container also submitted the same batch (and it may not be empty for that fork).\n\t\tconst firstMessage = batchStart.keyMessage;\n\t\t// -1 length is for back compat, undefined length means we actually don't know it\n\t\tconst skipLengthCheck =\n\t\t\tpendingMessage.batchInfo.length === -1 || batchLength === undefined;\n\t\tconst expectedPendingBatchLength =\n\t\t\tbatchLength === 0\n\t\t\t\t? 1 // For an empty batch, expect a singleton array with the empty batch marker\n\t\t\t\t: batchLength; // Otherwise, the lengths should actually match\n\n\t\t// Note: We don't need to use getEffectiveBatchId here, just check the explicit stamped batchID\n\t\t// That logic is needed only when comparing across potential container forks.\n\t\t// Furthermore, we also are comparing the batch IDs constituent data - clientId (it's local) and batchStartCsn.\n\t\tconst pendingBatchId = asBatchMetadata(pendingMessage.opMetadata)?.batchId;\n\t\tconst inboundBatchId = batchStart.batchId;\n\n\t\t// We expect the incoming batch to be of the same length, starting at the same clientSequenceNumber,\n\t\t// as the batch we originally submitted. The batchIds should match as well, if set (or neither should be set)\n\t\t// We have another later check to compare the message contents, which we'd expect to fail if this check does,\n\t\t// so we don't throw here, merely log. In a later release this check may replace that one since it's cheaper.\n\t\tif (\n\t\t\tpendingMessage.batchInfo.batchStartCsn !== batchStart.batchStartCsn ||\n\t\t\t(!skipLengthCheck && pendingMessage.batchInfo.length !== expectedPendingBatchLength) ||\n\t\t\tpendingBatchId !== inboundBatchId\n\t\t) {\n\t\t\tthis.logger?.sendErrorEvent({\n\t\t\t\teventName: \"BatchInfoMismatch\",\n\t\t\t\tdetails: {\n\t\t\t\t\tpendingBatchCsn: pendingMessage.batchInfo.batchStartCsn,\n\t\t\t\t\tbatchStartCsn: batchStart.batchStartCsn,\n\t\t\t\t\tpendingBatchLength: pendingMessage.batchInfo.length,\n\t\t\t\t\texpectedPendingBatchLength,\n\t\t\t\t\tbatchLength,\n\t\t\t\t\tpendingBatchId,\n\t\t\t\t\tinboundBatchId,\n\t\t\t\t\tpendingMessageBatchMetadata: asBatchMetadata(pendingMessage.opMetadata)?.batch,\n\t\t\t\t\tmessageBatchMetadata: asBatchMetadata(firstMessage?.metadata)?.batch,\n\t\t\t\t},\n\t\t\t\tmessageDetails: firstMessage && extractSafePropertiesFromMessage(firstMessage),\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending\n\t * states in its queue. This includes triggering resubmission of unacked ops.\n\t * ! Note: successfully resubmitting an op that has been successfully sequenced is not possible due to checks in the ConnectionStateHandler (Loader layer)\n\t */\n\tpublic replayPendingStates(): void {\n\t\tassert(\n\t\t\tthis.stateHandler.connected(),\n\t\t\t0x172 /* \"The connection state is not consistent with the runtime\" */,\n\t\t);\n\n\t\t// This assert suggests we are about to send same ops twice, which will result in data loss.\n\t\tassert(\n\t\t\tthis.clientIdFromLastReplay !== this.stateHandler.clientId(),\n\t\t\t0x173 /* \"replayPendingStates called twice for same clientId!\" */,\n\t\t);\n\t\tthis.clientIdFromLastReplay = this.stateHandler.clientId();\n\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x174 /* \"initial states should be empty before replaying pending\" */,\n\t\t);\n\n\t\tconst initialPendingMessagesCount = this.pendingMessages.length;\n\t\tlet remainingPendingMessagesCount = this.pendingMessages.length;\n\n\t\t// Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were\n\t\t// pending when we connected. This is important because the `reSubmitFn` might add more items in the queue\n\t\t// which must not be replayed.\n\t\twhile (remainingPendingMessagesCount > 0) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tlet pendingMessage = this.pendingMessages.shift()!;\n\t\t\tremainingPendingMessagesCount--;\n\n\t\t\tconst batchMetadataFlag = asBatchMetadata(pendingMessage.opMetadata)?.batch;\n\t\t\tassert(batchMetadataFlag !== false, 0x41b /* We cannot process batches in chunks */);\n\n\t\t\t// The next message starts a batch (possibly single-message), and we'll need its batchId.\n\t\t\tconst batchId = getEffectiveBatchId(pendingMessage);\n\n\t\t\tif (asEmptyBatchLocalOpMetadata(pendingMessage.localOpMetadata)?.emptyBatch === true) {\n\t\t\t\t// Resubmit no messages, with the batchId. Will result in another empty batch marker.\n\t\t\t\tthis.stateHandler.reSubmitBatch([], batchId);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * We must preserve the distinct batches on resubmit.\n\t\t\t * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will\n\t\t\t * either receive the whole batch ack or nothing at all. See {@link InboundBatchAggregator} for how this works.\n\t\t\t */\n\t\t\tif (batchMetadataFlag === undefined) {\n\t\t\t\t// Single-message batch\n\n\t\t\t\tthis.stateHandler.reSubmitBatch(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tbatchId,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// else: batchMetadataFlag === true (It's a typical multi-message batch)\n\n\t\t\tassert(\n\t\t\t\tremainingPendingMessagesCount > 0,\n\t\t\t\t0x554 /* Last pending message cannot be a batch begin */,\n\t\t\t);\n\n\t\t\tconst batch: PendingMessageResubmitData[] = [];\n\n\t\t\t// check is >= because batch end may be last pending message\n\t\t\twhile (remainingPendingMessagesCount >= 0) {\n\t\t\t\tbatch.push({\n\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t});\n\n\t\t\t\tif (pendingMessage.opMetadata?.batch === false) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tassert(remainingPendingMessagesCount > 0, 0x555 /* No batch end found */);\n\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tpendingMessage = this.pendingMessages.shift()!;\n\t\t\t\tremainingPendingMessagesCount--;\n\t\t\t\tassert(\n\t\t\t\t\tpendingMessage.opMetadata?.batch !== true,\n\t\t\t\t\t0x556 /* Batch start needs a corresponding batch end */,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.stateHandler.reSubmitBatch(batch, batchId);\n\t\t}\n\n\t\t// pending ops should no longer depend on previous sequenced local ops after resubmit\n\t\tthis.savedOps = [];\n\n\t\t// We replayPendingStates on read connections too - we expect these to get nack'd though, and to then reconnect\n\t\t// on a write connection and replay again. This filters out the replay that happens on the read connection so\n\t\t// we only see the replays on write connections (that have a chance to go through).\n\t\tif (this.stateHandler.isActiveConnection()) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"PendingStatesReplayed\",\n\t\t\t\tcount: initialPendingMessagesCount,\n\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * For back-compat if trying to apply stashed ops that pre-date batchInfo\n */\nfunction patchbatchInfo(\n\tmessage: IPendingMessageFromStash,\n): asserts message is IPendingMessage {\n\tconst batchInfo: IPendingMessageFromStash[\"batchInfo\"] = message.batchInfo;\n\tif (batchInfo === undefined) {\n\t\t// Using uuid guarantees uniqueness, retaining existing behavior\n\t\tmessage.batchInfo = { clientId: uuid(), batchStartCsn: -1, length: -1 };\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeLayerCompatState.d.ts","sourceRoot":"","sources":["../src/runtimeLayerCompatState.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;;;GAGG;AACH,eAAO,MAAM,wBAAwB;IACpC;;OAEG;;IAEH;;OAEG;;CAEH,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,mBAM3C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,+BAUvC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gCAAgC,EAAE,mBAM9C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,+BAU1C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,2BAA2B,CAC1C,kCAAkC,EAAE,mBAAmB,GAAG,SAAS,EACnE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,uBAAuB,KAAK,IAAI,GAClD,IAAI,CAoBN;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC7C,2BAA2B,EAAE,mBAAmB,GAAG,SAAS,EAC5D,SAAS,EAAE,MAAM,IAAI,GACnB,IAAI,CAoBN"}
1
+ {"version":3,"file":"runtimeLayerCompatState.d.ts","sourceRoot":"","sources":["../src/runtimeLayerCompatState.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;AAMrF;;;GAGG;AACH,eAAO,MAAM,wBAAwB;IACpC;;OAEG;;IAEH;;OAEG;;CAEH,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,mBAM3C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,+BAUvC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gCAAgC,EAAE,mBAM9C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,+BAU1C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,2BAA2B,CAC1C,kCAAkC,EAAE,mBAAmB,GAAG,SAAS,EACnE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,uBAAuB,KAAK,IAAI,GAClD,IAAI,CAoBN;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC7C,2BAA2B,EAAE,mBAAmB,GAAG,SAAS,EAC5D,SAAS,EAAE,MAAM,IAAI,GACnB,IAAI,CAoBN"}