@fluidframework/container-loader 0.59.2000-63294 → 0.59.3000-66610

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 (90) hide show
  1. package/.eslintrc.js +0 -1
  2. package/README.md +4 -4
  3. package/dist/collabWindowTracker.js +5 -5
  4. package/dist/collabWindowTracker.js.map +1 -1
  5. package/dist/connectionManager.d.ts.map +1 -1
  6. package/dist/connectionManager.js +32 -32
  7. package/dist/connectionManager.js.map +1 -1
  8. package/dist/connectionStateHandler.js +9 -9
  9. package/dist/connectionStateHandler.js.map +1 -1
  10. package/dist/container.d.ts +2 -1
  11. package/dist/container.d.ts.map +1 -1
  12. package/dist/container.js +76 -71
  13. package/dist/container.js.map +1 -1
  14. package/dist/containerContext.js +2 -2
  15. package/dist/containerContext.js.map +1 -1
  16. package/dist/containerStorageAdapter.d.ts.map +1 -1
  17. package/dist/containerStorageAdapter.js.map +1 -1
  18. package/dist/contracts.js +1 -1
  19. package/dist/contracts.js.map +1 -1
  20. package/dist/deltaManager.d.ts.map +1 -1
  21. package/dist/deltaManager.js +27 -27
  22. package/dist/deltaManager.js.map +1 -1
  23. package/dist/deltaQueue.d.ts.map +1 -1
  24. package/dist/deltaQueue.js +1 -1
  25. package/dist/deltaQueue.js.map +1 -1
  26. package/dist/loader.d.ts +2 -0
  27. package/dist/loader.d.ts.map +1 -1
  28. package/dist/loader.js +9 -9
  29. package/dist/loader.js.map +1 -1
  30. package/dist/packageVersion.d.ts +1 -1
  31. package/dist/packageVersion.js +1 -1
  32. package/dist/packageVersion.js.map +1 -1
  33. package/dist/protocolTreeDocumentStorageService.d.ts +2 -2
  34. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  35. package/dist/protocolTreeDocumentStorageService.js +1 -1
  36. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  37. package/dist/quorum.d.ts +4 -1
  38. package/dist/quorum.d.ts.map +1 -1
  39. package/dist/quorum.js +25 -6
  40. package/dist/quorum.js.map +1 -1
  41. package/dist/retriableDocumentStorageService.js +2 -2
  42. package/dist/retriableDocumentStorageService.js.map +1 -1
  43. package/dist/utils.d.ts +1 -0
  44. package/dist/utils.d.ts.map +1 -1
  45. package/dist/utils.js +11 -7
  46. package/dist/utils.js.map +1 -1
  47. package/lib/connectionManager.d.ts.map +1 -1
  48. package/lib/connectionManager.js.map +1 -1
  49. package/lib/connectionStateHandler.js +2 -2
  50. package/lib/connectionStateHandler.js.map +1 -1
  51. package/lib/container.d.ts +2 -1
  52. package/lib/container.d.ts.map +1 -1
  53. package/lib/container.js +28 -23
  54. package/lib/container.js.map +1 -1
  55. package/lib/containerContext.js.map +1 -1
  56. package/lib/containerStorageAdapter.d.ts.map +1 -1
  57. package/lib/containerStorageAdapter.js.map +1 -1
  58. package/lib/contracts.js.map +1 -1
  59. package/lib/deltaManager.d.ts.map +1 -1
  60. package/lib/deltaManager.js.map +1 -1
  61. package/lib/deltaQueue.d.ts.map +1 -1
  62. package/lib/deltaQueue.js.map +1 -1
  63. package/lib/loader.d.ts +2 -0
  64. package/lib/loader.d.ts.map +1 -1
  65. package/lib/loader.js.map +1 -1
  66. package/lib/packageVersion.d.ts +1 -1
  67. package/lib/packageVersion.js +1 -1
  68. package/lib/packageVersion.js.map +1 -1
  69. package/lib/protocolTreeDocumentStorageService.d.ts +2 -2
  70. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  71. package/lib/quorum.d.ts +4 -1
  72. package/lib/quorum.d.ts.map +1 -1
  73. package/lib/quorum.js +18 -1
  74. package/lib/quorum.js.map +1 -1
  75. package/lib/utils.d.ts +1 -0
  76. package/lib/utils.d.ts.map +1 -1
  77. package/lib/utils.js +3 -0
  78. package/lib/utils.js.map +1 -1
  79. package/package.json +12 -11
  80. package/src/connectionManager.ts +2 -3
  81. package/src/connectionStateHandler.ts +6 -6
  82. package/src/container.ts +55 -49
  83. package/src/containerStorageAdapter.ts +4 -4
  84. package/src/contracts.ts +8 -8
  85. package/src/deltaManager.ts +5 -8
  86. package/src/deltaQueue.ts +2 -4
  87. package/src/loader.ts +5 -3
  88. package/src/packageVersion.ts +1 -1
  89. package/src/quorum.ts +26 -1
  90. package/src/utils.ts +6 -2
package/src/container.ts CHANGED
@@ -89,6 +89,7 @@ import {
89
89
  normalizeError,
90
90
  MonitoringContext,
91
91
  loggerToMonitoringContext,
92
+ wrapError,
92
93
  } from "@fluidframework/telemetry-utils";
93
94
  import { Audience } from "./audience";
94
95
  import { ContainerContext } from "./containerContext";
@@ -101,8 +102,8 @@ import { ConnectionStateHandler, ILocalSequencedClient } from "./connectionState
101
102
  import { RetriableDocumentStorageService } from "./retriableDocumentStorageService";
102
103
  import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService";
103
104
  import { BlobOnlyStorage, ContainerStorageAdapter } from "./containerStorageAdapter";
104
- import { getSnapshotTreeFromSerializedContainer } from "./utils";
105
- import { QuorumProxy } from "./quorum";
105
+ import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
106
+ import { initQuorumValuesFromCodeDetails, getCodeDetailsFromQuorumValues, QuorumProxy } from "./quorum";
106
107
  import { CollabWindowTracker } from "./collabWindowTracker";
107
108
  import { ConnectionManager } from "./connectionManager";
108
109
 
@@ -166,17 +167,27 @@ export enum ConnectionState {
166
167
  * @returns true: container is up to date, it processed all the ops that were know at the time of first connection
167
168
  * false: storage does not provide indication of how far the client is. Container processed
168
169
  * all the ops known to it, but it maybe still behind.
170
+ * @throws an error beginning with `"Container closed"` if the container is closed before it catches up.
169
171
  */
170
172
  export async function waitContainerToCatchUp(container: IContainer) {
171
173
  // Make sure we stop waiting if container is closed.
172
174
  if (container.closed) {
173
- throw new Error("Container is closed");
175
+ throw new UsageError("waitContainerToCatchUp: Container closed");
174
176
  }
175
177
 
176
178
  return new Promise<boolean>((resolve, reject) => {
177
179
  const deltaManager = container.deltaManager;
178
180
 
179
- container.on("closed", reject);
181
+ const closedCallback = (err?: ICriticalContainerError | undefined) => {
182
+ container.off("closed", closedCallback);
183
+ const baseMessage = "Container closed while waiting to catch up";
184
+ reject(
185
+ err !== undefined
186
+ ? wrapError(err, (innerMessage) => new GenericError(`${baseMessage}: ${innerMessage}`))
187
+ : new GenericError(baseMessage),
188
+ );
189
+ };
190
+ container.on("closed", closedCallback);
180
191
 
181
192
  const waitForOps = () => {
182
193
  assert(container.connectionState !== ConnectionState.Disconnected,
@@ -187,11 +198,13 @@ export async function waitContainerToCatchUp(container: IContainer) {
187
198
  assert(deltaManager.lastSequenceNumber <= connectionOpSeqNumber,
188
199
  0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
189
200
  if (deltaManager.lastSequenceNumber === connectionOpSeqNumber) {
201
+ container.off("closed", closedCallback);
190
202
  resolve(hasCheckpointSequenceNumber);
191
203
  return;
192
204
  }
193
205
  const callbackOps = (message: ISequencedDocumentMessage) => {
194
206
  if (connectionOpSeqNumber <= message.sequenceNumber) {
207
+ container.off("closed", closedCallback);
195
208
  resolve(hasCheckpointSequenceNumber);
196
209
  deltaManager.off("op", callbackOps);
197
210
  }
@@ -517,11 +530,11 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
517
530
  return this._dirtyContainer;
518
531
  }
519
532
 
520
- private get serviceFactory() {return this.loader.services.documentServiceFactory;}
521
- private get urlResolver() {return this.loader.services.urlResolver;}
533
+ private get serviceFactory() { return this.loader.services.documentServiceFactory; }
534
+ private get urlResolver() { return this.loader.services.urlResolver; }
522
535
  public readonly options: ILoaderOptions;
523
- private get scope() { return this.loader.services.scope;}
524
- private get codeLoader() { return this.loader.services.codeLoader;}
536
+ private get scope() { return this.loader.services.scope; }
537
+ private get codeLoader() { return this.loader.services.codeLoader; }
525
538
 
526
539
  constructor(
527
540
  private readonly loader: Loader,
@@ -726,7 +739,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
726
739
  // Driver need to ensure all caches are cleared on critical errors
727
740
  this.service?.dispose(error);
728
741
  } catch (exception) {
729
- this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException"}, exception);
742
+ this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
730
743
  }
731
744
 
732
745
  this.mc.logger.sendTelemetryEvent(
@@ -885,7 +898,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
885
898
  if (!this.closed) {
886
899
  this.resumeInternal({ fetchOpsFromStorage: false, reason: "createDetached" });
887
900
  }
888
- } catch(error) {
901
+ } catch (error) {
889
902
  // add resolved URL on error object so that host has the ability to find this document and delete it
890
903
  const newError = normalizeError(error);
891
904
  const resolvedUrl = this.resolvedUrl;
@@ -956,11 +969,9 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
956
969
  public connect() {
957
970
  if (this.closed) {
958
971
  throw new UsageError(`The Container is closed and cannot be connected`);
959
- }
960
- else if (this._attachState !== AttachState.Attached) {
972
+ } else if (this._attachState !== AttachState.Attached) {
961
973
  throw new UsageError(`The Container is not attached and cannot be connected`);
962
- }
963
- else if (!this.connected) {
974
+ } else if (!this.connected) {
964
975
  // Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler().
965
976
  // If there is gap, we will learn about it once connected, but the gap should be small (if any),
966
977
  // assuming that connect() is called quickly after initial container boot.
@@ -984,8 +995,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
984
995
  public disconnect() {
985
996
  if (this.closed) {
986
997
  throw new UsageError(`The Container is closed and cannot be disconnected`);
987
- }
988
- else {
998
+ } else {
989
999
  this.disconnectInternal();
990
1000
  }
991
1001
  }
@@ -1053,8 +1063,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1053
1063
  }
1054
1064
 
1055
1065
  return this.protocolHandler.quorum.propose("code", codeDetails)
1056
- .then(()=>true)
1057
- .catch(()=>false);
1066
+ .then(() => true)
1067
+ .catch(() => false);
1058
1068
  }
1059
1069
 
1060
1070
  private async processCodeProposal(): Promise<void> {
@@ -1166,7 +1176,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1166
1176
  // ...load in the existing quorum
1167
1177
  // Initialize the protocol handler
1168
1178
  this._protocolHandler =
1169
- await this.loadAndInitializeProtocolState(attributes, this.storageService, snapshot);
1179
+ await this.initializeProtocolStateFromSnapshot(attributes, this.storageService, snapshot);
1170
1180
 
1171
1181
  const codeDetails = this.getCodeDetailsFromQuorum();
1172
1182
  await this.instantiateContext(
@@ -1233,27 +1243,16 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1233
1243
  minimumSequenceNumber: 0,
1234
1244
  };
1235
1245
 
1236
- // Seed the base quorum to be an empty list with a code quorum set
1237
- const committedCodeProposal: ICommittedProposal = {
1238
- key: "code",
1239
- value: source,
1240
- approvalSequenceNumber: 0,
1241
- commitSequenceNumber: 0,
1242
- sequenceNumber: 0,
1243
- };
1244
-
1245
- const members: [string, ISequencedClient][] = [];
1246
- const proposals: [number, ISequencedProposal, string[]][] = [];
1247
- const values: [string, ICommittedProposal][] = [["code", committedCodeProposal]];
1248
-
1249
1246
  await this.attachDeltaManagerOpHandler(attributes);
1250
1247
 
1251
1248
  // Need to just seed the source data in the code quorum. Quorum itself is empty
1249
+ const qValues = initQuorumValuesFromCodeDetails(source);
1252
1250
  this._protocolHandler = await this.initializeProtocolState(
1253
1251
  attributes,
1254
- members,
1255
- proposals,
1256
- values);
1252
+ [], // members
1253
+ [], // proposals
1254
+ qValues,
1255
+ );
1257
1256
 
1258
1257
  // The load context - given we seeded the quorum - will be great
1259
1258
  await this.instantiateContextDetached(
@@ -1275,13 +1274,22 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1275
1274
  const snapshotTree = getSnapshotTreeFromSerializedContainer(detachedContainerSnapshot);
1276
1275
  this._storage.loadSnapshotForRehydratingContainer(snapshotTree);
1277
1276
  const attributes = await this.getDocumentAttributes(this._storage, snapshotTree);
1278
- assert(attributes.sequenceNumber === 0, 0x0db /* "Seq number in detached container should be 0!!" */);
1277
+
1279
1278
  await this.attachDeltaManagerOpHandler(attributes);
1280
1279
 
1281
- // ...load in the existing quorum
1282
1280
  // Initialize the protocol handler
1281
+ const baseTree = getProtocolSnapshotTree(snapshotTree);
1282
+ const qValues = await readAndParse<[string, ICommittedProposal][]>(
1283
+ this._storage,
1284
+ baseTree.blobs.quorumValues,
1285
+ );
1286
+ const codeDetails = getCodeDetailsFromQuorumValues(qValues);
1283
1287
  this._protocolHandler =
1284
- await this.loadAndInitializeProtocolState(attributes, this._storage, snapshotTree);
1288
+ await this.initializeProtocolState(
1289
+ attributes,
1290
+ [], // members
1291
+ [], // proposals
1292
+ codeDetails !== undefined ? initQuorumValuesFromCodeDetails(codeDetails) : []);
1285
1293
 
1286
1294
  await this.instantiateContextDetached(
1287
1295
  true, // existing
@@ -1304,10 +1312,10 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1304
1312
  this._storageService =
1305
1313
  new RetriableDocumentStorageService(storageService, this.mc.logger);
1306
1314
 
1307
- if(this.options.summarizeProtocolTree === true) {
1308
- this.mc.logger.sendTelemetryEvent({eventName:"summarizeProtocolTreeEnabled"});
1315
+ if (this.options.summarizeProtocolTree === true) {
1316
+ this.mc.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
1309
1317
  this._storageService =
1310
- new ProtocolTreeStorageService(this._storageService, ()=>this.captureProtocolSummary());
1318
+ new ProtocolTreeStorageService(this._storageService, () => this.captureProtocolSummary());
1311
1319
  }
1312
1320
 
1313
1321
  // ensure we did not lose that policy in the process of wrapping
@@ -1342,7 +1350,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1342
1350
  return attributes;
1343
1351
  }
1344
1352
 
1345
- private async loadAndInitializeProtocolState(
1353
+ private async initializeProtocolStateFromSnapshot(
1346
1354
  attributes: IDocumentAttributes,
1347
1355
  storage: IDocumentStorageService,
1348
1356
  snapshot: ISnapshotTree | undefined,
@@ -1352,7 +1360,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1352
1360
  let values: [string, any][] = [];
1353
1361
 
1354
1362
  if (snapshot !== undefined) {
1355
- const baseTree = ".protocol" in snapshot.trees ? snapshot.trees[".protocol"] : snapshot;
1363
+ const baseTree = getProtocolSnapshotTree(snapshot);
1356
1364
  [members, proposals, values] = await Promise.all([
1357
1365
  readAndParse<[string, ISequencedClient][]>(storage, baseTree.blobs.quorumMembers),
1358
1366
  readAndParse<[number, ISequencedProposal, string[]][]>(storage, baseTree.blobs.quorumProposals),
@@ -1561,8 +1569,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1561
1569
 
1562
1570
  private async attachDeltaManagerOpHandler(
1563
1571
  attributes: IDocumentAttributes,
1564
- prefetchType?: "cached" | "all" | "none")
1565
- {
1572
+ prefetchType?: "cached" | "all" | "none") {
1566
1573
  return this._deltaManager.attachOpHandler(
1567
1574
  attributes.minimumSequenceNumber,
1568
1575
  attributes.sequenceNumber,
@@ -1668,7 +1675,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1668
1675
  // this can be removed once all clients send
1669
1676
  // protocol tree by default
1670
1677
  const summary = contents as ISummaryContent;
1671
- if(summary.details === undefined) {
1678
+ if (summary.details === undefined) {
1672
1679
  summary.details = {};
1673
1680
  }
1674
1681
  summary.details.includesProtocolTree =
@@ -1740,7 +1747,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1740
1747
  private processSignal(message: ISignalMessage) {
1741
1748
  // No clientId indicates a system signal message.
1742
1749
  if (message.clientId === null) {
1743
- const innerContent = message.content as { content: any; type: string };
1750
+ const innerContent = message.content as { content: any; type: string; };
1744
1751
  if (innerContent.type === MessageType.ClientJoin) {
1745
1752
  const newClient = innerContent.content as ISignalClient;
1746
1753
  this._audience.addMember(newClient.clientId, newClient.client);
@@ -1760,8 +1767,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1760
1767
  * @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
1761
1768
  */
1762
1769
  private async fetchSnapshotTree(specifiedVersion: string | undefined):
1763
- Promise<{snapshot?: ISnapshotTree; versionId?: string}>
1764
- {
1770
+ Promise<{ snapshot?: ISnapshotTree; versionId?: string; }> {
1765
1771
  const version = await this.getVersion(specifiedVersion ?? null);
1766
1772
 
1767
1773
  if (version === undefined && specifiedVersion !== undefined) {
@@ -25,7 +25,7 @@ import { ISnapshotTreeWithBlobContents } from "./utils";
25
25
  * container attach state.
26
26
  */
27
27
  export class ContainerStorageAdapter implements IDocumentStorageService {
28
- private readonly blobContents: {[id: string]: ArrayBufferLike} = {};
28
+ private readonly blobContents: { [id: string]: ArrayBufferLike; } = {};
29
29
  constructor(private readonly storageGetter: () => IDocumentStorageService) {}
30
30
 
31
31
  public loadSnapshotForRehydratingContainer(snapshotTree: ISnapshotTreeWithBlobContents) {
@@ -33,10 +33,10 @@ export class ContainerStorageAdapter implements IDocumentStorageService {
33
33
  }
34
34
 
35
35
  private getBlobContents(snapshotTree: ISnapshotTreeWithBlobContents) {
36
- for(const [id, value] of Object.entries(snapshotTree.blobsContents)) {
36
+ for (const [id, value] of Object.entries(snapshotTree.blobsContents)) {
37
37
  this.blobContents[id] = value;
38
38
  }
39
- for(const [_, tree] of Object.entries(snapshotTree.trees)) {
39
+ for (const [_, tree] of Object.entries(snapshotTree.trees)) {
40
40
  this.getBlobContents(tree);
41
41
  }
42
42
  }
@@ -46,7 +46,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService {
46
46
  // and storage is always present in >=0.41.
47
47
  try {
48
48
  return this.storageGetter().policies;
49
- } catch(e) {}
49
+ } catch (e) {}
50
50
  return undefined;
51
51
  }
52
52
 
package/src/contracts.ts CHANGED
@@ -112,13 +112,13 @@ export interface IConnectionManagerFactoryArgs {
112
112
  * Called by connection manager for each incomming op. Some ops maybe delivered before
113
113
  * connectHandler is called (initial ops on socket connection)
114
114
  */
115
- readonly incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) => void,
115
+ readonly incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) => void;
116
116
 
117
117
  /**
118
118
  * Called by connection manager for each incoming signals.
119
119
  * Maybe called before connectHandler is called (initial signals on socket connection)
120
120
  */
121
- readonly signalHandler: (message: ISignalMessage) => void,
121
+ readonly signalHandler: (message: ISignalMessage) => void;
122
122
 
123
123
  /**
124
124
  * Called when connection manager experiences delay in connecting to relay service.
@@ -126,28 +126,28 @@ export interface IConnectionManagerFactoryArgs {
126
126
  * Can be called many times while not connected.
127
127
  * Situation is considered resolved when connection is established and connectHandler is called.
128
128
  */
129
- readonly reconnectionDelayHandler: (delayMs: number, error: unknown) => void,
129
+ readonly reconnectionDelayHandler: (delayMs: number, error: unknown) => void;
130
130
 
131
131
  /**
132
132
  * Called by connection manager whwnever critical error happens and container should be closed.
133
133
  * Expects dispose() call in respose to this call.
134
134
  */
135
- readonly closeHandler: (error?: any) => void,
135
+ readonly closeHandler: (error?: any) => void;
136
136
 
137
137
  /**
138
138
  * Called whenever connection to relay service is lost.
139
139
  */
140
- readonly disconnectHandler: (reason: string) => void,
140
+ readonly disconnectHandler: (reason: string) => void;
141
141
 
142
142
  /**
143
143
  * Called whenever new connection to rely service is established
144
144
  */
145
- readonly connectHandler: (connection: IConnectionDetails) => void,
145
+ readonly connectHandler: (connection: IConnectionDetails) => void;
146
146
 
147
147
  /**
148
148
  * Called whenever ping/pong messages are roundtripped on connection.
149
149
  */
150
- readonly pongHandler: (latency: number) => void,
150
+ readonly pongHandler: (latency: number) => void;
151
151
 
152
152
  /**
153
153
  * Called whenever connection type changes from writable to read-only or vice versa.
@@ -156,7 +156,7 @@ export interface IConnectionManagerFactoryArgs {
156
156
  * This should not be confused with "read" / "write"connection mode which is internal
157
157
  * optimization.
158
158
  */
159
- readonly readonlyChangeHandler: (readonly?: boolean) => void,
159
+ readonly readonlyChangeHandler: (readonly?: boolean) => void;
160
160
  }
161
161
 
162
162
  /**
@@ -77,8 +77,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
77
77
  extends TypedEventEmitter<IDeltaManagerInternalEvents>
78
78
  implements
79
79
  IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
80
- IEventProvider<IDeltaManagerInternalEvents>
81
- {
80
+ IEventProvider<IDeltaManagerInternalEvents> {
82
81
  public readonly connectionManager: TConnectionManager;
83
82
 
84
83
  public get active(): boolean { return this._active(); }
@@ -268,7 +267,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
268
267
  ) {
269
268
  super();
270
269
  const props: IConnectionManagerFactoryArgs = {
271
- incomingOpHandler:(messages: ISequencedDocumentMessage[], reason: string) =>
270
+ incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) =>
272
271
  this.enqueueMessages(messages, reason),
273
272
  signalHandler: (message: ISignalMessage) => this._inboundSignal.push(message),
274
273
  reconnectionDelayHandler: (delayMs: number, error: unknown) =>
@@ -440,8 +439,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
440
439
  from: number, // inclusive
441
440
  to: number | undefined, // exclusive
442
441
  callback: (messages: ISequencedDocumentMessage[]) => void,
443
- cacheOnly: boolean)
444
- {
442
+ cacheOnly: boolean) {
445
443
  const docService = this.serviceProvider();
446
444
  if (docService === undefined) {
447
445
  throw new Error("Delta manager is not attached");
@@ -820,8 +818,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
820
818
  private async fetchMissingDeltasCore(
821
819
  reason: string,
822
820
  cacheOnly: boolean,
823
- to?: number)
824
- {
821
+ to?: number) {
825
822
  // Exit out early if we're already fetching deltas
826
823
  if (this.fetchReason !== undefined) {
827
824
  return;
@@ -865,7 +862,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
865
862
  },
866
863
  cacheOnly);
867
864
  } catch (error) {
868
- this.logger.sendErrorEvent({eventName: "GetDeltas_Exception"}, error);
865
+ this.logger.sendErrorEvent({ eventName: "GetDeltas_Exception" }, error);
869
866
  this.close(normalizeError(error));
870
867
  } finally {
871
868
  this.refreshDelayInfo(this.deltaStorageDelayId);
package/src/deltaQueue.ts CHANGED
@@ -7,16 +7,14 @@ import { IDeltaQueue, IDeltaQueueEvents } from "@fluidframework/container-defini
7
7
  import { assert, performance, Deferred, TypedEventEmitter } from "@fluidframework/common-utils";
8
8
  import Deque from "double-ended-queue";
9
9
 
10
- export interface IDeltaQueueWriter<T>
11
- {
10
+ export interface IDeltaQueueWriter<T> {
12
11
  push(task: T): void;
13
12
  clear(): void;
14
13
  }
15
14
 
16
15
  export class DeltaQueue<T>
17
16
  extends TypedEventEmitter<IDeltaQueueEvents<T>>
18
- implements IDeltaQueue<T>, IDeltaQueueWriter<T>
19
- {
17
+ implements IDeltaQueue<T>, IDeltaQueueWriter<T> {
20
18
  private isDisposed: boolean = false;
21
19
  private readonly q = new Deque<T>();
22
20
 
package/src/loader.ts CHANGED
@@ -80,7 +80,7 @@ export class RelativeLoader implements ILoader {
80
80
  {
81
81
  canReconnect: request.headers?.[LoaderHeader.reconnect],
82
82
  clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
83
- resolvedUrl: {...resolvedUrl},
83
+ resolvedUrl: { ...resolvedUrl },
84
84
  version: request.headers?.[LoaderHeader.version] ?? undefined,
85
85
  loadMode: request.headers?.[LoaderHeader.loadMode],
86
86
  },
@@ -129,7 +129,7 @@ function createCachedResolver(resolver: IUrlResolver) {
129
129
  }
130
130
 
131
131
  export interface ILoaderOptions extends ILoaderOptions1{
132
- summarizeProtocolTree?: boolean,
132
+ summarizeProtocolTree?: boolean;
133
133
  }
134
134
 
135
135
  /**
@@ -203,6 +203,7 @@ export interface ILoaderProps {
203
203
  /**
204
204
  * Proxy loader factories for loading containers via proxy in other contexts,
205
205
  * like web workers, or worker threads.
206
+ * @deprecated Not recommended for general use and will be removed in an upcoming release.
206
207
  */
207
208
  readonly proxyLoaderFactories?: Map<string, IProxyLoaderFactory>;
208
209
 
@@ -259,6 +260,7 @@ export interface ILoaderServices {
259
260
  /**
260
261
  * Proxy loader factories for loading containers via proxy in other contexts,
261
262
  * like web workers, or worker threads.
263
+ * @deprecated Not recommended for general use and will be removed in an upcoming release.
262
264
  */
263
265
  readonly proxyLoaderFactories: Map<string, IProxyLoaderFactory>;
264
266
 
@@ -393,7 +395,7 @@ export class Loader implements IHostLoader {
393
395
  private async resolveCore(
394
396
  request: IRequest,
395
397
  pendingLocalState?: IPendingLocalState,
396
- ): Promise<{ container: Container; parsed: IParsedUrl }> {
398
+ ): Promise<{ container: Container; parsed: IParsedUrl; }> {
397
399
  const resolvedAsFluid = await this.services.urlResolver.resolve(request);
398
400
  ensureFluidResolvedUrl(resolvedAsFluid);
399
401
 
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "0.59.2000-63294";
9
+ export const pkgVersion = "0.59.3000-66610";
package/src/quorum.ts CHANGED
@@ -2,8 +2,10 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { EventForwarder, doIfNotDisposed } from "@fluidframework/common-utils";
5
+ import { assert, EventForwarder, doIfNotDisposed } from "@fluidframework/common-utils";
6
+ import { IFluidCodeDetails } from "@fluidframework/core-interfaces";
6
7
  import {
8
+ ICommittedProposal,
7
9
  IQuorum,
8
10
  IQuorumEvents,
9
11
  ISequencedClient,
@@ -32,3 +34,26 @@ export class QuorumProxy extends EventForwarder<IQuorumEvents> implements IQuoru
32
34
  this.getMember = doIfNotDisposed(this, quorum.getMember.bind(quorum));
33
35
  }
34
36
  }
37
+
38
+ export function getCodeDetailsFromQuorumValues(
39
+ quorumValues: [string, ICommittedProposal][],
40
+ ): IFluidCodeDetails {
41
+ const qValuesMap = new Map(quorumValues);
42
+ const proposal = qValuesMap.get("code");
43
+ assert(proposal !== undefined, 0x2dc /* "Cannot find code proposal" */);
44
+ return proposal?.value as IFluidCodeDetails;
45
+ }
46
+
47
+ export function initQuorumValuesFromCodeDetails(
48
+ source: IFluidCodeDetails,
49
+ ): [string, ICommittedProposal][] {
50
+ // Seed the base quorum to be an empty list with a code quorum set
51
+ const committedCodeProposal: ICommittedProposal = {
52
+ key: "code",
53
+ value: source,
54
+ approvalSequenceNumber: 0,
55
+ commitSequenceNumber: 0,
56
+ sequenceNumber: 0,
57
+ };
58
+ return [["code", committedCodeProposal]];
59
+ }
package/src/utils.ts CHANGED
@@ -16,8 +16,8 @@ import { ISummaryTree, ISnapshotTree, SummaryType } from "@fluidframework/protoc
16
16
  // This is used when we rehydrate a container from the snapshot. Here we put the blob contents
17
17
  // in separate property: blobContents.
18
18
  export interface ISnapshotTreeWithBlobContents extends ISnapshotTree {
19
- blobsContents: {[path: string]: ArrayBufferLike},
20
- trees: {[path: string]: ISnapshotTreeWithBlobContents},
19
+ blobsContents: { [path: string]: ArrayBufferLike; };
20
+ trees: { [path: string]: ISnapshotTreeWithBlobContents; };
21
21
  }
22
22
 
23
23
  export interface IParsedUrl {
@@ -130,3 +130,7 @@ export const getSnapshotTreeFromSerializedContainer = (detachedContainerSnapshot
130
130
  );
131
131
  return snapshotTreeWithBlobContents;
132
132
  };
133
+
134
+ export function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {
135
+ return ".protocol" in snapshot.trees ? snapshot.trees[".protocol"] : snapshot;
136
+ }