@fluidframework/container-runtime 2.70.0-361788 → 2.71.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 (78) hide show
  1. package/.eslintrc.cjs +5 -1
  2. package/CHANGELOG.md +14 -0
  3. package/container-runtime.test-files.tar +0 -0
  4. package/dist/channelCollection.d.ts +66 -17
  5. package/dist/channelCollection.d.ts.map +1 -1
  6. package/dist/channelCollection.js +118 -84
  7. package/dist/channelCollection.js.map +1 -1
  8. package/dist/containerRuntime.d.ts +19 -11
  9. package/dist/containerRuntime.d.ts.map +1 -1
  10. package/dist/containerRuntime.js +146 -52
  11. package/dist/containerRuntime.js.map +1 -1
  12. package/dist/dataStore.d.ts +3 -1
  13. package/dist/dataStore.d.ts.map +1 -1
  14. package/dist/dataStore.js +8 -9
  15. package/dist/dataStore.js.map +1 -1
  16. package/dist/dataStoreContext.d.ts +6 -5
  17. package/dist/dataStoreContext.d.ts.map +1 -1
  18. package/dist/dataStoreContext.js +7 -4
  19. package/dist/dataStoreContext.js.map +1 -1
  20. package/dist/index.d.ts +3 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/messageTypes.d.ts +17 -4
  24. package/dist/messageTypes.d.ts.map +1 -1
  25. package/dist/messageTypes.js.map +1 -1
  26. package/dist/packageVersion.d.ts +1 -1
  27. package/dist/packageVersion.d.ts.map +1 -1
  28. package/dist/packageVersion.js +1 -1
  29. package/dist/packageVersion.js.map +1 -1
  30. package/dist/runtimeLayerCompatState.d.ts +2 -2
  31. package/dist/runtimeLayerCompatState.d.ts.map +1 -1
  32. package/dist/runtimeLayerCompatState.js.map +1 -1
  33. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  34. package/dist/summary/summarizerNode/summarizerNode.js +3 -1
  35. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  36. package/lib/channelCollection.d.ts +66 -17
  37. package/lib/channelCollection.d.ts.map +1 -1
  38. package/lib/channelCollection.js +115 -82
  39. package/lib/channelCollection.js.map +1 -1
  40. package/lib/containerRuntime.d.ts +19 -11
  41. package/lib/containerRuntime.d.ts.map +1 -1
  42. package/lib/containerRuntime.js +148 -53
  43. package/lib/containerRuntime.js.map +1 -1
  44. package/lib/dataStore.d.ts +3 -1
  45. package/lib/dataStore.d.ts.map +1 -1
  46. package/lib/dataStore.js +3 -4
  47. package/lib/dataStore.js.map +1 -1
  48. package/lib/dataStoreContext.d.ts +6 -5
  49. package/lib/dataStoreContext.d.ts.map +1 -1
  50. package/lib/dataStoreContext.js +8 -5
  51. package/lib/dataStoreContext.js.map +1 -1
  52. package/lib/index.d.ts +3 -1
  53. package/lib/index.d.ts.map +1 -1
  54. package/lib/index.js +1 -1
  55. package/lib/index.js.map +1 -1
  56. package/lib/messageTypes.d.ts +17 -4
  57. package/lib/messageTypes.d.ts.map +1 -1
  58. package/lib/messageTypes.js.map +1 -1
  59. package/lib/packageVersion.d.ts +1 -1
  60. package/lib/packageVersion.d.ts.map +1 -1
  61. package/lib/packageVersion.js +1 -1
  62. package/lib/packageVersion.js.map +1 -1
  63. package/lib/runtimeLayerCompatState.d.ts +2 -2
  64. package/lib/runtimeLayerCompatState.d.ts.map +1 -1
  65. package/lib/runtimeLayerCompatState.js.map +1 -1
  66. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  67. package/lib/summary/summarizerNode/summarizerNode.js +3 -1
  68. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  69. package/package.json +22 -30
  70. package/src/channelCollection.ts +255 -109
  71. package/src/containerRuntime.ts +262 -92
  72. package/src/dataStore.ts +12 -10
  73. package/src/dataStoreContext.ts +45 -39
  74. package/src/index.ts +8 -3
  75. package/src/messageTypes.ts +17 -2
  76. package/src/packageVersion.ts +1 -1
  77. package/src/runtimeLayerCompatState.ts +1 -1
  78. package/src/summary/summarizerNode/summarizerNode.ts +1 -0
@@ -25,9 +25,11 @@ import { nonDataStorePaths, rootHasIsolatedChannels, } from "./summary/index.js"
25
25
  */
26
26
  export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
27
27
  /**
28
- * Creates a shallow wrapper of {@link IFluidParentContext}. The wrapper can then have its methods overwritten as needed
28
+ * Creates a shallow wrapper of {@link IFluidParentContextPrivate} or
29
+ * {@link IFluidRootParentContextPrivate} with `submitMessage` and `submitSignal`
30
+ * methods replaced with the provided overrides.
29
31
  */
30
- export function wrapContext(context) {
32
+ export function formParentContext(context, overrides) {
31
33
  return {
32
34
  get IFluidDataStoreRegistry() {
33
35
  return context.IFluidDataStoreRegistry;
@@ -67,12 +69,8 @@ export function wrapContext(context) {
67
69
  getAudience: (...args) => {
68
70
  return context.getAudience(...args);
69
71
  },
70
- submitMessage: (...args) => {
71
- return context.submitMessage(...args);
72
- },
73
- submitSignal: (...args) => {
74
- return context.submitSignal(...args);
75
- },
72
+ submitMessage: overrides.submitMessage.bind(overrides),
73
+ submitSignal: overrides.submitSignal,
76
74
  makeLocallyVisible: (...args) => {
77
75
  return context.makeLocallyVisible(...args);
78
76
  },
@@ -92,36 +90,34 @@ export function wrapContext(context) {
92
90
  return context.setChannelDirty(address);
93
91
  },
94
92
  minVersionForCollab: context.minVersionForCollab,
93
+ getExtension: context.getExtension.bind(context),
95
94
  };
96
95
  }
97
96
  /**
98
- * Creates a wrapper of a {@link IFluidParentContext} to be provided to the inner datastore channels.
97
+ * Creates a wrapper of a {@link IFluidRootParentContextPrivate} to be provided to the inner datastore channels.
99
98
  * The wrapper will have the submit methods overwritten with the appropriate id as the destination address.
100
99
  *
101
100
  * @param id - the id of the channel
102
- * @param parentContext - the {@link IFluidParentContext} to wrap
101
+ * @param parentContext - the {@link IFluidRootParentContextPrivate} to wrap
103
102
  * @returns A wrapped {@link IFluidParentContext}
104
103
  */
105
104
  function wrapContextForInnerChannel(id, parentContext) {
106
- const context = wrapContext(parentContext);
107
- context.submitMessage = (type, content, localOpMetadata) => {
108
- const fluidDataStoreContent = {
109
- content,
110
- type,
111
- };
112
- const envelope = {
113
- address: id,
114
- contents: fluidDataStoreContent,
115
- };
116
- parentContext.submitMessage(ContainerMessageType.FluidDataStoreOp, envelope, localOpMetadata);
117
- };
118
- context.submitSignal = (type, contents, targetClientId) => {
119
- const envelope = {
120
- address: id,
121
- contents,
122
- };
123
- parentContext.submitSignal(type, envelope, targetClientId);
124
- };
105
+ const context = formParentContext(parentContext, {
106
+ submitMessage: (type, content, localOpMetadata) => {
107
+ const fluidDataStoreContent = {
108
+ content,
109
+ type,
110
+ };
111
+ const envelope = {
112
+ address: id,
113
+ contents: fluidDataStoreContent,
114
+ };
115
+ parentContext.submitMessage({ type: ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
116
+ },
117
+ submitSignal: (type, content, targetClientId) => {
118
+ parentContext.submitSignal({ address: id, contents: { type, content } }, targetClientId);
119
+ },
120
+ });
125
121
  return context;
126
122
  }
127
123
  /**
@@ -136,7 +132,7 @@ export function getLocalDataStoreType(localDataStore) {
136
132
  * @internal
137
133
  */
138
134
  export class ChannelCollection {
139
- constructor(baseSnapshot, parentContext, baseLogger, gcNodeUpdated, isDataStoreDeleted, aliasMap, provideEntryPoint) {
135
+ constructor(baseSnapshot, parentContext, baseLogger, gcNodeUpdated, isDataStoreDeleted, aliasMap) {
140
136
  this.baseSnapshot = baseSnapshot;
141
137
  this.parentContext = parentContext;
142
138
  this.gcNodeUpdated = gcNodeUpdated;
@@ -153,9 +149,49 @@ export class ChannelCollection {
153
149
  * For sampling. Only log once per container
154
150
  */
155
151
  this.shouldSendAttachLog = true;
152
+ this.reSubmitContainerMessage = (message, localOpMetadata, squash) => {
153
+ switch (message.type) {
154
+ case ContainerMessageType.Attach:
155
+ case ContainerMessageType.Alias: {
156
+ this.parentContext.submitMessage(message, localOpMetadata);
157
+ return;
158
+ }
159
+ case ContainerMessageType.FluidDataStoreOp: {
160
+ return this.resubmitDataStoreOp(message.contents, localOpMetadata, squash);
161
+ }
162
+ default: {
163
+ assert(false, 0x907 /* unknown op type */);
164
+ }
165
+ }
166
+ };
167
+ this.resubmitDataStoreOp = (envelope, localOpMetadata, squash) => {
168
+ const context = this.contexts.get(envelope.address);
169
+ // If the data store has been deleted, log an error and throw an error. If there are local changes for a
170
+ // deleted data store, it can otherwise lead to inconsistent state when compared to other clients.
171
+ if (this.checkAndLogIfDeleted(envelope.address, context, "Changed", "resubmitDataStoreOp")) {
172
+ throw new DataCorruptionError("Context is deleted!", {
173
+ callSite: "resubmitDataStoreOp",
174
+ ...tagCodeArtifacts({ id: envelope.address }),
175
+ });
176
+ }
177
+ assert(!!context, 0x160 /* "There should be a store context for the op" */);
178
+ context.reSubmit(envelope.contents, localOpMetadata, squash);
179
+ };
180
+ this.rollbackDataStoreOp = (envelope, localOpMetadata) => {
181
+ const context = this.contexts.get(envelope.address);
182
+ // If the data store has been deleted, log an error and throw an error. If there are local changes for a
183
+ // deleted data store, it can otherwise lead to inconsistent state when compared to other clients.
184
+ if (this.checkAndLogIfDeleted(envelope.address, context, "Changed", "rollbackDataStoreOp")) {
185
+ throw new DataCorruptionError("Context is deleted!", {
186
+ callSite: "rollbackDataStoreOp",
187
+ ...tagCodeArtifacts({ id: envelope.address }),
188
+ });
189
+ }
190
+ assert(!!context, 0x2e8 /* "There should be a store context for the op" */);
191
+ context.rollback(envelope.contents, localOpMetadata);
192
+ };
156
193
  this.mc = createChildMonitoringContext({ logger: baseLogger });
157
194
  this.contexts = new DataStoreContexts(baseLogger);
158
- this.entryPoint = new FluidObjectHandle(new LazyPromise(async () => provideEntryPoint(this)), "", this.parentContext.IFluidHandleContext);
159
195
  this.aliasedDataStores = new Set(aliasMap.values());
160
196
  // Extract stores stored inside the snapshot
161
197
  const fluidDataStores = new Map();
@@ -398,7 +434,7 @@ export class ChannelCollection {
398
434
  submitAttachChannelOp(localContext) {
399
435
  const message = this.generateAttachMessage(localContext);
400
436
  this.pendingAttach.set(localContext.id, message);
401
- this.parentContext.submitMessage(ContainerMessageType.Attach, message, undefined);
437
+ this.parentContext.submitMessage({ type: ContainerMessageType.Attach, contents: message }, undefined);
402
438
  this.attachOpFiredForDataStore.add(localContext.id);
403
439
  }
404
440
  /**
@@ -472,52 +508,6 @@ export class ChannelCollection {
472
508
  dispose() {
473
509
  return this.disposeOnce.value;
474
510
  }
475
- reSubmit(type, content, localOpMetadata, squash) {
476
- switch (type) {
477
- case ContainerMessageType.Attach:
478
- case ContainerMessageType.Alias: {
479
- this.parentContext.submitMessage(type, content, localOpMetadata);
480
- return;
481
- }
482
- case ContainerMessageType.FluidDataStoreOp: {
483
- return this.reSubmitChannelOp(type, content, localOpMetadata, squash);
484
- }
485
- default: {
486
- assert(false, 0x907 /* unknown op type */);
487
- }
488
- }
489
- }
490
- reSubmitChannelOp(type, content, localOpMetadata, squash) {
491
- const envelope = content;
492
- const context = this.contexts.get(envelope.address);
493
- // If the data store has been deleted, log an error and throw an error. If there are local changes for a
494
- // deleted data store, it can otherwise lead to inconsistent state when compared to other clients.
495
- if (this.checkAndLogIfDeleted(envelope.address, context, "Changed", "resubmitDataStoreOp")) {
496
- throw new DataCorruptionError("Context is deleted!", {
497
- callSite: "resubmitDataStoreOp",
498
- ...tagCodeArtifacts({ id: envelope.address }),
499
- });
500
- }
501
- assert(!!context, 0x160 /* "There should be a store context for the op" */);
502
- const innerContents = envelope.contents;
503
- context.reSubmit(innerContents.type, innerContents.content, localOpMetadata, squash);
504
- }
505
- rollback(type, content, localOpMetadata) {
506
- assert(type === ContainerMessageType.FluidDataStoreOp, 0x8e8 /* type */);
507
- const envelope = content;
508
- const context = this.contexts.get(envelope.address);
509
- // If the data store has been deleted, log an error and throw an error. If there are local changes for a
510
- // deleted data store, it can otherwise lead to inconsistent state when compared to other clients.
511
- if (this.checkAndLogIfDeleted(envelope.address, context, "Changed", "rollbackDataStoreOp")) {
512
- throw new DataCorruptionError("Context is deleted!", {
513
- callSite: "rollbackDataStoreOp",
514
- ...tagCodeArtifacts({ id: envelope.address }),
515
- });
516
- }
517
- assert(!!context, 0x2e8 /* "There should be a store context for the op" */);
518
- const innerContents = envelope.contents;
519
- context.rollback(innerContents.type, innerContents.content, localOpMetadata);
520
- }
521
511
  async applyStashedOp(content) {
522
512
  const opContents = content;
523
513
  switch (opContents.type) {
@@ -1229,7 +1219,50 @@ export function detectOutboundReferences(address, contents, addedOutboundReferen
1229
1219
  addedOutboundReference(fromPath, toPath);
1230
1220
  }
1231
1221
  }
1222
+ // #region Experimentation
1223
+ // The code below here is for experimentation (and one test) only.
1232
1224
  /**
1225
+ * @privateRemarks This class is only used for experimentation/testing.
1226
+ */
1227
+ export class ComposableChannelCollection extends ChannelCollection {
1228
+ constructor(baseSnapshot, parentContext, baseLogger, gcNodeUpdated, isDataStoreDeleted, aliasMap, provideEntryPoint) {
1229
+ super(baseSnapshot,
1230
+ /* [root] parentContext */
1231
+ formParentContext(parentContext, {
1232
+ submitMessage: (containerRuntimeMessage, localOpMetadata) => {
1233
+ // Note that here our message format is reconfigured.
1234
+ // While `ContainerRuntime*Message`s use `contents`
1235
+ // as `FluidDataStoreMessage`s, the content is
1236
+ // stored in `content`.
1237
+ parentContext.submitMessage(containerRuntimeMessage.type, containerRuntimeMessage.contents, localOpMetadata);
1238
+ },
1239
+ submitSignal: (envelope, targetClientId) => {
1240
+ parentContext.submitSignal(envelope.contents.type, {
1241
+ address: envelope.address,
1242
+ contents: envelope.contents.content,
1243
+ }, targetClientId);
1244
+ },
1245
+ }), baseLogger, gcNodeUpdated, isDataStoreDeleted, aliasMap);
1246
+ this.entryPoint = new FluidObjectHandle(new LazyPromise(async () => provideEntryPoint(this)), "", this.parentContext.IFluidHandleContext);
1247
+ }
1248
+ reSubmit(type, content, localOpMetadata, squash) {
1249
+ // If the cast is incorrect and type is not one of the three supported,
1250
+ // reSubmitContainerMessage will assert.
1251
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Need to force conversion
1252
+ const message = {
1253
+ type,
1254
+ contents: content,
1255
+ };
1256
+ this.reSubmitContainerMessage(message, localOpMetadata, squash);
1257
+ }
1258
+ rollback(type, content, localOpMetadata) {
1259
+ assert(type === ContainerMessageType.FluidDataStoreOp, 0x8e8 /* type */);
1260
+ this.rollbackDataStoreOp(content, localOpMetadata);
1261
+ }
1262
+ }
1263
+ /**
1264
+ * @privateRemarks This factory is only used for experimentation/testing.
1265
+ *
1233
1266
  * @internal
1234
1267
  */
1235
1268
  export class ChannelCollectionFactory {
@@ -1254,10 +1287,10 @@ export class ChannelCollectionFactory {
1254
1287
  // this factory and the container runtime are
1255
1288
  // from the same package.
1256
1289
  assert(context instanceof FluidDataStoreContext, 0xb8f /* we don't support the layer boundary here today */);
1257
- const runtime = new ChannelCollection(context.baseSnapshot, context, // parentContext
1258
- context.baseLogger, () => { }, // gcNodeUpdated
1259
- (_nodePath) => false, // isDataStoreDeleted
1260
- new Map(), // aliasMap
1290
+ const runtime = new ComposableChannelCollection(context.baseSnapshot,
1291
+ /* parentContext */ context, context.baseLogger,
1292
+ /* gcNodeUpdated */ () => { },
1293
+ /* isDataStoreDeleted */ (_nodePath) => false, new Map(), // aliasMap
1261
1294
  this.provideEntryPoint);
1262
1295
  return runtime;
1263
1296
  }