@fluidframework/container-loader 2.0.0-rc.3.0.2 → 2.0.0-rc.4.0.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 (188) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/api-report/container-loader.api.md +5 -1
  3. package/dist/attachment.d.ts +3 -2
  4. package/dist/attachment.d.ts.map +1 -1
  5. package/dist/attachment.js +5 -5
  6. package/dist/attachment.js.map +1 -1
  7. package/dist/audience.d.ts +6 -4
  8. package/dist/audience.d.ts.map +1 -1
  9. package/dist/audience.js +18 -3
  10. package/dist/audience.js.map +1 -1
  11. package/dist/catchUpMonitor.d.ts +1 -1
  12. package/dist/catchUpMonitor.d.ts.map +1 -1
  13. package/dist/catchUpMonitor.js.map +1 -1
  14. package/dist/connectionManager.d.ts +7 -3
  15. package/dist/connectionManager.d.ts.map +1 -1
  16. package/dist/connectionManager.js +57 -38
  17. package/dist/connectionManager.js.map +1 -1
  18. package/dist/connectionStateHandler.d.ts +31 -10
  19. package/dist/connectionStateHandler.d.ts.map +1 -1
  20. package/dist/connectionStateHandler.js +49 -36
  21. package/dist/connectionStateHandler.js.map +1 -1
  22. package/dist/container.d.ts +22 -13
  23. package/dist/container.d.ts.map +1 -1
  24. package/dist/container.js +145 -117
  25. package/dist/container.js.map +1 -1
  26. package/dist/containerContext.d.ts +3 -3
  27. package/dist/containerContext.d.ts.map +1 -1
  28. package/dist/containerContext.js.map +1 -1
  29. package/dist/containerStorageAdapter.d.ts +12 -3
  30. package/dist/containerStorageAdapter.d.ts.map +1 -1
  31. package/dist/containerStorageAdapter.js +42 -4
  32. package/dist/containerStorageAdapter.js.map +1 -1
  33. package/dist/contracts.d.ts +2 -2
  34. package/dist/contracts.d.ts.map +1 -1
  35. package/dist/contracts.js.map +1 -1
  36. package/dist/debugLogger.d.ts +1 -2
  37. package/dist/debugLogger.d.ts.map +1 -1
  38. package/dist/debugLogger.js.map +1 -1
  39. package/dist/deltaManager.d.ts +5 -6
  40. package/dist/deltaManager.d.ts.map +1 -1
  41. package/dist/deltaManager.js +29 -24
  42. package/dist/deltaManager.js.map +1 -1
  43. package/dist/deltaQueue.d.ts +1 -1
  44. package/dist/deltaQueue.d.ts.map +1 -1
  45. package/dist/deltaQueue.js.map +1 -1
  46. package/dist/error.d.ts +1 -2
  47. package/dist/error.d.ts.map +1 -1
  48. package/dist/error.js.map +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +3 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/legacy.d.ts +2 -2
  54. package/dist/loadPaused.d.ts +35 -0
  55. package/dist/loadPaused.d.ts.map +1 -0
  56. package/dist/loadPaused.js +115 -0
  57. package/dist/loadPaused.js.map +1 -0
  58. package/dist/loader.d.ts +1 -1
  59. package/dist/loader.d.ts.map +1 -1
  60. package/dist/loader.js +1 -14
  61. package/dist/loader.js.map +1 -1
  62. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  63. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +4 -4
  64. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  65. package/dist/packageVersion.d.ts +1 -1
  66. package/dist/packageVersion.js +1 -1
  67. package/dist/packageVersion.js.map +1 -1
  68. package/dist/protocol.d.ts.map +1 -1
  69. package/dist/protocol.js +3 -0
  70. package/dist/protocol.js.map +1 -1
  71. package/dist/public.d.ts +1 -1
  72. package/dist/retriableDocumentStorageService.d.ts +1 -1
  73. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  74. package/dist/retriableDocumentStorageService.js.map +1 -1
  75. package/dist/serializedStateManager.d.ts +89 -9
  76. package/dist/serializedStateManager.d.ts.map +1 -1
  77. package/dist/serializedStateManager.js +150 -34
  78. package/dist/serializedStateManager.js.map +1 -1
  79. package/dist/utils.d.ts +11 -1
  80. package/dist/utils.d.ts.map +1 -1
  81. package/dist/utils.js +29 -14
  82. package/dist/utils.js.map +1 -1
  83. package/lib/attachment.d.ts +3 -2
  84. package/lib/attachment.d.ts.map +1 -1
  85. package/lib/attachment.js +5 -5
  86. package/lib/attachment.js.map +1 -1
  87. package/lib/audience.d.ts +6 -4
  88. package/lib/audience.d.ts.map +1 -1
  89. package/lib/audience.js +19 -4
  90. package/lib/audience.js.map +1 -1
  91. package/lib/catchUpMonitor.d.ts +1 -1
  92. package/lib/catchUpMonitor.d.ts.map +1 -1
  93. package/lib/catchUpMonitor.js.map +1 -1
  94. package/lib/connectionManager.d.ts +7 -3
  95. package/lib/connectionManager.d.ts.map +1 -1
  96. package/lib/connectionManager.js +36 -17
  97. package/lib/connectionManager.js.map +1 -1
  98. package/lib/connectionStateHandler.d.ts +31 -10
  99. package/lib/connectionStateHandler.d.ts.map +1 -1
  100. package/lib/connectionStateHandler.js +49 -36
  101. package/lib/connectionStateHandler.js.map +1 -1
  102. package/lib/container.d.ts +22 -13
  103. package/lib/container.d.ts.map +1 -1
  104. package/lib/container.js +146 -118
  105. package/lib/container.js.map +1 -1
  106. package/lib/containerContext.d.ts +3 -3
  107. package/lib/containerContext.d.ts.map +1 -1
  108. package/lib/containerContext.js.map +1 -1
  109. package/lib/containerStorageAdapter.d.ts +12 -3
  110. package/lib/containerStorageAdapter.d.ts.map +1 -1
  111. package/lib/containerStorageAdapter.js +42 -4
  112. package/lib/containerStorageAdapter.js.map +1 -1
  113. package/lib/contracts.d.ts +2 -2
  114. package/lib/contracts.d.ts.map +1 -1
  115. package/lib/contracts.js +1 -1
  116. package/lib/contracts.js.map +1 -1
  117. package/lib/debugLogger.d.ts +1 -2
  118. package/lib/debugLogger.d.ts.map +1 -1
  119. package/lib/debugLogger.js.map +1 -1
  120. package/lib/deltaManager.d.ts +5 -6
  121. package/lib/deltaManager.d.ts.map +1 -1
  122. package/lib/deltaManager.js +10 -5
  123. package/lib/deltaManager.js.map +1 -1
  124. package/lib/deltaQueue.d.ts +1 -1
  125. package/lib/deltaQueue.d.ts.map +1 -1
  126. package/lib/deltaQueue.js.map +1 -1
  127. package/lib/error.d.ts +1 -2
  128. package/lib/error.d.ts.map +1 -1
  129. package/lib/error.js.map +1 -1
  130. package/lib/index.d.ts +1 -0
  131. package/lib/index.d.ts.map +1 -1
  132. package/lib/index.js +1 -0
  133. package/lib/index.js.map +1 -1
  134. package/lib/legacy.d.ts +2 -2
  135. package/lib/loadPaused.d.ts +35 -0
  136. package/lib/loadPaused.d.ts.map +1 -0
  137. package/lib/loadPaused.js +111 -0
  138. package/lib/loadPaused.js.map +1 -0
  139. package/lib/loader.d.ts +1 -1
  140. package/lib/loader.d.ts.map +1 -1
  141. package/lib/loader.js +3 -16
  142. package/lib/loader.js.map +1 -1
  143. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  144. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +1 -1
  145. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  146. package/lib/packageVersion.d.ts +1 -1
  147. package/lib/packageVersion.js +1 -1
  148. package/lib/packageVersion.js.map +1 -1
  149. package/lib/protocol.d.ts.map +1 -1
  150. package/lib/protocol.js +3 -0
  151. package/lib/protocol.js.map +1 -1
  152. package/lib/public.d.ts +1 -1
  153. package/lib/retriableDocumentStorageService.d.ts +1 -1
  154. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  155. package/lib/retriableDocumentStorageService.js +1 -1
  156. package/lib/retriableDocumentStorageService.js.map +1 -1
  157. package/lib/serializedStateManager.d.ts +89 -9
  158. package/lib/serializedStateManager.d.ts.map +1 -1
  159. package/lib/serializedStateManager.js +146 -30
  160. package/lib/serializedStateManager.js.map +1 -1
  161. package/lib/tsdoc-metadata.json +1 -1
  162. package/lib/utils.d.ts +11 -1
  163. package/lib/utils.d.ts.map +1 -1
  164. package/lib/utils.js +15 -1
  165. package/lib/utils.js.map +1 -1
  166. package/package.json +24 -21
  167. package/src/attachment.ts +12 -13
  168. package/src/audience.ts +30 -9
  169. package/src/catchUpMonitor.ts +1 -1
  170. package/src/connectionManager.ts +45 -22
  171. package/src/connectionStateHandler.ts +78 -45
  172. package/src/container.ts +181 -160
  173. package/src/containerContext.ts +2 -2
  174. package/src/containerStorageAdapter.ts +61 -6
  175. package/src/contracts.ts +5 -4
  176. package/src/debugLogger.ts +1 -1
  177. package/src/deltaManager.ts +15 -8
  178. package/src/deltaQueue.ts +1 -1
  179. package/src/error.ts +1 -1
  180. package/src/index.ts +1 -0
  181. package/src/loadPaused.ts +140 -0
  182. package/src/loader.ts +6 -23
  183. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +1 -1
  184. package/src/packageVersion.ts +1 -1
  185. package/src/protocol.ts +4 -0
  186. package/src/retriableDocumentStorageService.ts +5 -2
  187. package/src/serializedStateManager.ts +215 -48
  188. package/src/utils.ts +19 -1
@@ -3,13 +3,14 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IDeltaManager } from "@fluidframework/container-definitions";
6
+ import { IDeltaManager } from "@fluidframework/container-definitions/internal";
7
7
  import { ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
8
8
  import { assert, Timer } from "@fluidframework/core-utils/internal";
9
- import { IAnyDriverError } from "@fluidframework/driver-definitions";
9
+ import { IAnyDriverError } from "@fluidframework/driver-definitions/internal";
10
10
  import { IClient, ISequencedClient } from "@fluidframework/protocol-definitions";
11
- import { ITelemetryLoggerExt, type TelemetryEventCategory } from "@fluidframework/telemetry-utils";
12
11
  import {
12
+ type TelemetryEventCategory,
13
+ ITelemetryLoggerExt,
13
14
  PerformanceEvent,
14
15
  loggerToMonitoringContext,
15
16
  } from "@fluidframework/telemetry-utils/internal";
@@ -25,7 +26,7 @@ import { IProtocolHandler } from "./protocol.js";
25
26
  const JoinOpTimeoutMs = 45000;
26
27
 
27
28
  // Timeout waiting for "self" join signal, before giving up
28
- const JoinSignalTimeoutMs = 5000;
29
+ const JoinSignalTimeoutMs = 10000;
29
30
 
30
31
  /** Constructor parameter type for passing in dependencies needed by the ConnectionStateHandler */
31
32
  export interface IConnectionStateHandlerInputs {
@@ -48,6 +49,9 @@ export interface IConnectionStateHandlerInputs {
48
49
  ) => void;
49
50
  /** Callback to note that an old local client ID is still present in the Quorum that should have left and should now be considered invalid */
50
51
  clientShouldHaveLeft: (clientId: string) => void;
52
+
53
+ /** Some critical error was hit. Container should be closed and error logged. */
54
+ onCriticalError: (error: unknown) => void;
51
55
  }
52
56
 
53
57
  /**
@@ -55,7 +59,19 @@ export interface IConnectionStateHandlerInputs {
55
59
  */
56
60
  export interface IConnectionStateHandler {
57
61
  readonly connectionState: ConnectionState;
62
+ /**
63
+ * Pending clientID.
64
+ * Changes whenever socket connection is established.
65
+ * Resets to undefined when connection is lost
66
+ */
58
67
  readonly pendingClientId: string | undefined;
68
+ /**
69
+ * clientId of a last established connection.
70
+ * Does not reset on disconnect.
71
+ * Changes only when new connection is established, client is fully caught up, and
72
+ * there is no chance to ops from previous connection (i.e. if needed, we have waited and observed leave op from previous connection)
73
+ */
74
+ readonly clientId: string | undefined;
59
75
 
60
76
  containerSaved(): void;
61
77
  dispose(): void;
@@ -78,8 +94,8 @@ export function createConnectionStateHandler(
78
94
  ) {
79
95
  const mc = loggerToMonitoringContext(inputs.logger);
80
96
  return createConnectionStateHandlerCore(
81
- mc.config.getBoolean("Fluid.Container.CatchUpBeforeDeclaringConnected") === true, // connectedRaisedWhenCaughtUp
82
- mc.config.getBoolean("Fluid.Container.EnableJoinSignalWait") === true, // readClientsWaitForJoinSignal
97
+ mc.config.getBoolean("Fluid.Container.DisableCatchUpBeforeDeclaringConnected") !== true, // connectedRaisedWhenCaughtUp
98
+ mc.config.getBoolean("Fluid.Container.DisableJoinSignalWait") !== true, // readClientsWaitForJoinSignal
83
99
  inputs,
84
100
  deltaManager,
85
101
  clientId,
@@ -93,15 +109,12 @@ export function createConnectionStateHandlerCore(
93
109
  deltaManager: IDeltaManager<any, any>,
94
110
  clientId?: string,
95
111
  ) {
96
- if (!connectedRaisedWhenCaughtUp) {
97
- return new ConnectionStateHandler(inputs, readClientsWaitForJoinSignal, clientId);
98
- }
99
- return new ConnectionStateCatchup(
100
- inputs,
101
- (handler: IConnectionStateHandlerInputs) =>
102
- new ConnectionStateHandler(handler, readClientsWaitForJoinSignal, clientId),
103
- deltaManager,
104
- );
112
+ const factory = (handler: IConnectionStateHandlerInputs) =>
113
+ new ConnectionStateHandler(handler, readClientsWaitForJoinSignal, clientId);
114
+
115
+ return connectedRaisedWhenCaughtUp
116
+ ? new ConnectionStateCatchup(inputs, factory, deltaManager)
117
+ : factory(inputs);
105
118
  }
106
119
 
107
120
  /**
@@ -140,6 +153,9 @@ class ConnectionStateHandlerPassThrough
140
153
  public get pendingClientId() {
141
154
  return this.pimpl.pendingClientId;
142
155
  }
156
+ public get clientId() {
157
+ return this.pimpl.clientId;
158
+ }
143
159
 
144
160
  public containerSaved() {
145
161
  return this.pimpl.containerSaved();
@@ -196,6 +212,10 @@ class ConnectionStateHandlerPassThrough
196
212
  public clientShouldHaveLeft(clientId: string) {
197
213
  return this.inputs.clientShouldHaveLeft(clientId);
198
214
  }
215
+
216
+ public onCriticalError(error: unknown) {
217
+ return this.inputs.onCriticalError(error);
218
+ }
199
219
  }
200
220
 
201
221
  /**
@@ -325,7 +345,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
325
345
  /**
326
346
  * Tracks that we observe our own "join" op within the timeout after receiving a "connected" event from the DeltaManager
327
347
  */
328
- private readonly joinOpTimer: Timer;
348
+ private readonly joinTimer: Timer;
329
349
 
330
350
  private protocol?: IProtocolHandler;
331
351
  private connection?: IConnectionDetailsInternal;
@@ -338,7 +358,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
338
358
  return this._connectionState;
339
359
  }
340
360
 
341
- private get clientId(): string | undefined {
361
+ public get clientId(): string | undefined {
342
362
  return this._clientId;
343
363
  }
344
364
 
@@ -352,6 +372,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
352
372
  clientIdFromPausedSession?: string,
353
373
  ) {
354
374
  this._clientId = clientIdFromPausedSession;
375
+ const errorHandler = (error) => this.handler.onCriticalError(error);
355
376
  this.prevClientLeftTimer = new Timer(
356
377
  // Default is 5 min for which we are going to wait for its own "leave" message. This is same as
357
378
  // the max time on server after which leave op is sent.
@@ -363,10 +384,11 @@ class ConnectionStateHandler implements IConnectionStateHandler {
363
384
  );
364
385
  this.applyForConnectedState("timeout");
365
386
  },
387
+ errorHandler,
366
388
  );
367
389
 
368
- this.joinOpTimer = new Timer(
369
- 0, // default value is not used - startJoinOpTimer() explicitly provides timeout
390
+ this.joinTimer = new Timer(
391
+ 0, // default value is not used - startjoinTimer() explicitly provides timeout
370
392
  () => {
371
393
  // I've observed timer firing within couple ms from disconnect event, looks like
372
394
  // queued timer callback is not cancelled if timer is cancelled while callback sits in the queue.
@@ -379,22 +401,27 @@ class ConnectionStateHandler implements IConnectionStateHandler {
379
401
  clientJoined: this.hasMember(this.pendingClientId),
380
402
  waitingForLeaveOp: this.waitingForLeaveOp,
381
403
  };
382
- this.handler.logConnectionIssue("NoJoinOp", "error", details);
404
+ this.handler.logConnectionIssue(
405
+ this.connection?.mode === "read" ? "NoJoinSignal" : "NoJoinOp", // eventName
406
+ "error", // category
407
+ details,
408
+ );
383
409
  },
410
+ errorHandler,
384
411
  );
385
412
  }
386
413
 
387
- private startJoinOpTimer() {
388
- assert(!this.joinOpTimer.hasTimer, 0x234 /* "has joinOpTimer" */);
414
+ private startjoinTimer() {
415
+ assert(!this.joinTimer.hasTimer, 0x234 /* "has joinTimer" */);
389
416
  assert(this.connection !== undefined, 0x4b3 /* have connection */);
390
- this.joinOpTimer.start(
417
+ this.joinTimer.start(
391
418
  this.connection.mode === "write" ? JoinOpTimeoutMs : JoinSignalTimeoutMs,
392
419
  );
393
420
  }
394
421
 
395
- private stopJoinOpTimer() {
396
- assert(this.joinOpTimer.hasTimer, 0x235 /* "no joinOpTimer" */);
397
- this.joinOpTimer.clear();
422
+ private stopjoinTimer() {
423
+ assert(this.joinTimer.hasTimer, 0x235 /* "no joinTimer" */);
424
+ this.joinTimer.clear();
398
425
  }
399
426
 
400
427
  private get waitingForLeaveOp() {
@@ -402,7 +429,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
402
429
  }
403
430
 
404
431
  public dispose() {
405
- assert(!this.joinOpTimer.hasTimer, 0x2a5 /* "join timer" */);
432
+ assert(!this.joinTimer.hasTimer, 0x2a5 /* "join timer" */);
406
433
  this.prevClientLeftTimer.clear();
407
434
  }
408
435
 
@@ -418,15 +445,18 @@ class ConnectionStateHandler implements IConnectionStateHandler {
418
445
  private receivedAddMemberEvent(clientId: string) {
419
446
  // This is the only one that requires the pending client ID
420
447
  if (clientId === this.pendingClientId) {
421
- if (this.joinOpTimer.hasTimer) {
422
- this.stopJoinOpTimer();
423
- } else if (this.shouldWaitForJoinSignal()) {
448
+ if (this.joinTimer.hasTimer) {
449
+ this.stopjoinTimer();
450
+ } else if (this.shouldWaitForSelf()) {
424
451
  // timer has already fired, meaning it took too long to get join op/signal.
425
452
  // Record how long it actually took to recover.
426
453
  // This is generic event, as it by itself is not an error.
427
454
  // We also have a case where NoJoinOp happens during container boot (we do not report it as error in such case),
428
455
  // if this log statement happens after boot - we do not want to consider it error case.
429
- this.handler.logConnectionIssue("ReceivedJoinOp", "generic");
456
+ this.handler.logConnectionIssue(
457
+ this.connection?.mode === "read" ? "ReceivedJoinSignal" : "ReceivedJoinOp", // eventName
458
+ "generic", // category
459
+ );
430
460
  }
431
461
  // Start the event in case we are waiting for leave or timeout.
432
462
  if (this.waitingForLeaveOp) {
@@ -514,7 +544,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
514
544
  this._connectionState === ConnectionState.EstablishingConnection,
515
545
  0x6d3 /* Connection state should be EstablishingConnection */,
516
546
  );
517
- assert(this.connection === undefined, 0x6d4 /* No connetion should be present */);
547
+ assert(this.connection === undefined, 0x6d4 /* No connection should be present */);
518
548
  const oldState = this._connectionState;
519
549
  this._connectionState = ConnectionState.Disconnected;
520
550
  this.handler.connectionStateChanged(ConnectionState.Disconnected, oldState, reason);
@@ -529,7 +559,12 @@ class ConnectionStateHandler implements IConnectionStateHandler {
529
559
  });
530
560
  }
531
561
 
532
- private shouldWaitForJoinSignal() {
562
+ /**
563
+ * Tells if need to wait for "self" to show up in audience.
564
+ * @returns - true if we should wait for "self" to appear in audience.
565
+ * false is returned only for "read" connections, and only if this.readClientsWaitForJoinSignal is false.
566
+ */
567
+ private shouldWaitForSelf() {
533
568
  assert(
534
569
  this.connection !== undefined,
535
570
  0x4b4 /* all callers call here with active connection */,
@@ -576,10 +611,10 @@ class ConnectionStateHandler implements IConnectionStateHandler {
576
611
  // We are fetching ops from storage in parallel to connecting to Relay Service,
577
612
  // and given async processes, it's possible that we have already processed our own join message before
578
613
  // connection was fully established.
579
- if (!this.hasMember(this._pendingClientId) && this.shouldWaitForJoinSignal()) {
614
+ if (!this.hasMember(this._pendingClientId) && this.shouldWaitForSelf()) {
580
615
  // We are waiting for our own join op / signal. When it is processed
581
616
  // we'll attempt to transition to Connected state via receivedAddMemberEvent() flow.
582
- this.startJoinOpTimer();
617
+ this.startjoinTimer();
583
618
  } else if (!this.waitingForLeaveOp) {
584
619
  // We're not waiting for Join or Leave op (if read-only connection those don't even apply),
585
620
  // go ahead and declare the state to be Connected!
@@ -628,8 +663,8 @@ class ConnectionStateHandler implements IConnectionStateHandler {
628
663
  // Clear pending state immediately to prepare for reconnect
629
664
  this._pendingClientId = undefined;
630
665
 
631
- if (this.joinOpTimer.hasTimer) {
632
- this.stopJoinOpTimer();
666
+ if (this.joinTimer.hasTimer) {
667
+ this.stopjoinTimer();
633
668
  }
634
669
 
635
670
  // Only wait for "leave" message if the connected client exists in the quorum and had some non-acked ops
@@ -660,15 +695,10 @@ class ConnectionStateHandler implements IConnectionStateHandler {
660
695
  this.handler.connectionStateChanged(this._connectionState, oldState, reason);
661
696
  }
662
697
 
663
- // Helper method to switch between quorum and audience.
664
- // Old design was checking only quorum for "write" clients.
665
- // Latest change checks audience for all types of connections.
666
698
  protected get membership(): IMembership | undefined {
667
- // We could always use audience here, and in practice it will probably be correct.
668
- // (including case when this.readClientsWaitForJoinSignal === false).
669
- // But only if it's superset of quorum, i.e. when filtered to "write" clients, they are always identical!
670
- // It's safer to assume that we have bugs and engaging kill-bit switch should bring us back to well-known
671
- // and tested state!
699
+ // We could always use audience here.
700
+ // This is true because Audience is a superset of quorum, i.e. when we filter Audience to "write" clients,
701
+ // it is exactly the same as quorum! Please see asserts in Audience callbacks setup by initProtocol() enforcing that.
672
702
  return this.readClientsWaitForJoinSignal ? this.protocol?.audience : this.protocol?.quorum;
673
703
  }
674
704
 
@@ -676,6 +706,9 @@ class ConnectionStateHandler implements IConnectionStateHandler {
676
706
  this.protocol = protocol;
677
707
 
678
708
  this.membership?.on("addMember", (clientId, details) => {
709
+ // This is very important constrain. We rely on it when testing presence of "self" in Audience.
710
+ // We do not want to move to "connected" state for "write" connections when JoinSignal shows up
711
+ // for "self" - we want to move to "connected" state only when "join" op is received.
679
712
  assert(
680
713
  (details as IClient).mode === "read" ||
681
714
  protocol.quorum.getMember(clientId) !== undefined,