@fluidframework/container-loader 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229

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 (168) hide show
  1. package/.eslintrc.js +18 -21
  2. package/.mocharc.js +2 -2
  3. package/README.md +65 -44
  4. package/api-extractor.json +2 -2
  5. package/closeAndGetPendingLocalState.md +51 -0
  6. package/dist/audience.d.ts +0 -1
  7. package/dist/audience.d.ts.map +1 -1
  8. package/dist/audience.js.map +1 -1
  9. package/dist/catchUpMonitor.d.ts.map +1 -1
  10. package/dist/catchUpMonitor.js.map +1 -1
  11. package/dist/collabWindowTracker.d.ts.map +1 -1
  12. package/dist/collabWindowTracker.js.map +1 -1
  13. package/dist/connectionManager.d.ts +5 -5
  14. package/dist/connectionManager.d.ts.map +1 -1
  15. package/dist/connectionManager.js +107 -44
  16. package/dist/connectionManager.js.map +1 -1
  17. package/dist/connectionState.d.ts.map +1 -1
  18. package/dist/connectionState.js.map +1 -1
  19. package/dist/connectionStateHandler.d.ts +7 -7
  20. package/dist/connectionStateHandler.d.ts.map +1 -1
  21. package/dist/connectionStateHandler.js +50 -21
  22. package/dist/connectionStateHandler.js.map +1 -1
  23. package/dist/container.d.ts +64 -5
  24. package/dist/container.d.ts.map +1 -1
  25. package/dist/container.js +329 -137
  26. package/dist/container.js.map +1 -1
  27. package/dist/containerContext.d.ts +19 -8
  28. package/dist/containerContext.d.ts.map +1 -1
  29. package/dist/containerContext.js +58 -14
  30. package/dist/containerContext.js.map +1 -1
  31. package/dist/containerStorageAdapter.d.ts +41 -2
  32. package/dist/containerStorageAdapter.d.ts.map +1 -1
  33. package/dist/containerStorageAdapter.js +88 -14
  34. package/dist/containerStorageAdapter.js.map +1 -1
  35. package/dist/contracts.d.ts +3 -3
  36. package/dist/contracts.d.ts.map +1 -1
  37. package/dist/contracts.js.map +1 -1
  38. package/dist/deltaManager.d.ts +21 -8
  39. package/dist/deltaManager.d.ts.map +1 -1
  40. package/dist/deltaManager.js +112 -37
  41. package/dist/deltaManager.js.map +1 -1
  42. package/dist/deltaManagerProxy.d.ts +10 -22
  43. package/dist/deltaManagerProxy.d.ts.map +1 -1
  44. package/dist/deltaManagerProxy.js +14 -50
  45. package/dist/deltaManagerProxy.js.map +1 -1
  46. package/dist/deltaQueue.d.ts.map +1 -1
  47. package/dist/deltaQueue.js +4 -2
  48. package/dist/deltaQueue.js.map +1 -1
  49. package/dist/index.d.ts +4 -3
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +1 -3
  52. package/dist/index.js.map +1 -1
  53. package/dist/loader.d.ts +13 -4
  54. package/dist/loader.d.ts.map +1 -1
  55. package/dist/loader.js +38 -24
  56. package/dist/loader.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/protocol.d.ts.map +1 -1
  61. package/dist/protocol.js +2 -1
  62. package/dist/protocol.js.map +1 -1
  63. package/dist/protocolTreeDocumentStorageService.d.ts +6 -2
  64. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  65. package/dist/protocolTreeDocumentStorageService.js +7 -4
  66. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  67. package/dist/quorum.d.ts.map +1 -1
  68. package/dist/quorum.js.map +1 -1
  69. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  70. package/dist/retriableDocumentStorageService.js +6 -2
  71. package/dist/retriableDocumentStorageService.js.map +1 -1
  72. package/dist/utils.d.ts.map +1 -1
  73. package/dist/utils.js +8 -5
  74. package/dist/utils.js.map +1 -1
  75. package/lib/audience.d.ts +0 -1
  76. package/lib/audience.d.ts.map +1 -1
  77. package/lib/audience.js.map +1 -1
  78. package/lib/catchUpMonitor.d.ts.map +1 -1
  79. package/lib/catchUpMonitor.js.map +1 -1
  80. package/lib/collabWindowTracker.d.ts.map +1 -1
  81. package/lib/collabWindowTracker.js.map +1 -1
  82. package/lib/connectionManager.d.ts +5 -5
  83. package/lib/connectionManager.d.ts.map +1 -1
  84. package/lib/connectionManager.js +110 -47
  85. package/lib/connectionManager.js.map +1 -1
  86. package/lib/connectionState.d.ts.map +1 -1
  87. package/lib/connectionState.js.map +1 -1
  88. package/lib/connectionStateHandler.d.ts +7 -7
  89. package/lib/connectionStateHandler.d.ts.map +1 -1
  90. package/lib/connectionStateHandler.js +50 -21
  91. package/lib/connectionStateHandler.js.map +1 -1
  92. package/lib/container.d.ts +64 -5
  93. package/lib/container.d.ts.map +1 -1
  94. package/lib/container.js +336 -144
  95. package/lib/container.js.map +1 -1
  96. package/lib/containerContext.d.ts +19 -8
  97. package/lib/containerContext.d.ts.map +1 -1
  98. package/lib/containerContext.js +59 -15
  99. package/lib/containerContext.js.map +1 -1
  100. package/lib/containerStorageAdapter.d.ts +41 -2
  101. package/lib/containerStorageAdapter.d.ts.map +1 -1
  102. package/lib/containerStorageAdapter.js +86 -14
  103. package/lib/containerStorageAdapter.js.map +1 -1
  104. package/lib/contracts.d.ts +3 -3
  105. package/lib/contracts.d.ts.map +1 -1
  106. package/lib/contracts.js.map +1 -1
  107. package/lib/deltaManager.d.ts +21 -8
  108. package/lib/deltaManager.d.ts.map +1 -1
  109. package/lib/deltaManager.js +114 -39
  110. package/lib/deltaManager.js.map +1 -1
  111. package/lib/deltaManagerProxy.d.ts +10 -22
  112. package/lib/deltaManagerProxy.d.ts.map +1 -1
  113. package/lib/deltaManagerProxy.js +14 -50
  114. package/lib/deltaManagerProxy.js.map +1 -1
  115. package/lib/deltaQueue.d.ts.map +1 -1
  116. package/lib/deltaQueue.js +4 -2
  117. package/lib/deltaQueue.js.map +1 -1
  118. package/lib/index.d.ts +4 -3
  119. package/lib/index.d.ts.map +1 -1
  120. package/lib/index.js +2 -2
  121. package/lib/index.js.map +1 -1
  122. package/lib/loader.d.ts +13 -4
  123. package/lib/loader.d.ts.map +1 -1
  124. package/lib/loader.js +37 -24
  125. package/lib/loader.js.map +1 -1
  126. package/lib/packageVersion.d.ts +1 -1
  127. package/lib/packageVersion.js +1 -1
  128. package/lib/packageVersion.js.map +1 -1
  129. package/lib/protocol.d.ts.map +1 -1
  130. package/lib/protocol.js +2 -1
  131. package/lib/protocol.js.map +1 -1
  132. package/lib/protocolTreeDocumentStorageService.d.ts +6 -2
  133. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  134. package/lib/protocolTreeDocumentStorageService.js +7 -4
  135. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  136. package/lib/quorum.d.ts.map +1 -1
  137. package/lib/quorum.js.map +1 -1
  138. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  139. package/lib/retriableDocumentStorageService.js +6 -2
  140. package/lib/retriableDocumentStorageService.js.map +1 -1
  141. package/lib/utils.d.ts.map +1 -1
  142. package/lib/utils.js +8 -5
  143. package/lib/utils.js.map +1 -1
  144. package/package.json +67 -56
  145. package/prettier.config.cjs +1 -1
  146. package/src/audience.ts +51 -46
  147. package/src/catchUpMonitor.ts +39 -37
  148. package/src/collabWindowTracker.ts +75 -70
  149. package/src/connectionManager.ts +1040 -941
  150. package/src/connectionState.ts +19 -19
  151. package/src/connectionStateHandler.ts +557 -463
  152. package/src/container.ts +2147 -1784
  153. package/src/containerContext.ts +417 -345
  154. package/src/containerStorageAdapter.ts +268 -154
  155. package/src/contracts.ts +155 -153
  156. package/src/deltaManager.ts +1074 -945
  157. package/src/deltaManagerProxy.ts +88 -137
  158. package/src/deltaQueue.ts +155 -151
  159. package/src/index.ts +13 -17
  160. package/src/loader.ts +434 -427
  161. package/src/packageVersion.ts +1 -1
  162. package/src/protocol.ts +93 -87
  163. package/src/protocolTreeDocumentStorageService.ts +34 -34
  164. package/src/quorum.ts +34 -34
  165. package/src/retriableDocumentStorageService.ts +118 -102
  166. package/src/utils.ts +93 -83
  167. package/tsconfig.esnext.json +6 -6
  168. package/tsconfig.json +8 -12
@@ -11,6 +11,7 @@ exports.ConnectionManager = void 0;
11
11
  const abort_controller_1 = __importDefault(require("abort-controller"));
12
12
  const common_utils_1 = require("@fluidframework/common-utils");
13
13
  const container_utils_1 = require("@fluidframework/container-utils");
14
+ const driver_definitions_1 = require("@fluidframework/driver-definitions");
14
15
  const driver_utils_1 = require("@fluidframework/driver-utils");
15
16
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
16
17
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
@@ -52,7 +53,9 @@ class NoDeltaStream extends common_utils_1.TypedEventEmitter {
52
53
  this.version = "";
53
54
  this.initialMessages = [];
54
55
  this.initialSignals = [];
55
- this.initialClients = [{ client: clientNoDeltaStream, clientId: clientIdNoDeltaStream }];
56
+ this.initialClients = [
57
+ { client: clientNoDeltaStream, clientId: clientIdNoDeltaStream },
58
+ ];
56
59
  this.serviceConfiguration = {
57
60
  maxMessageSize: 0,
58
61
  blockSize: 0,
@@ -74,9 +77,26 @@ class NoDeltaStream extends common_utils_1.TypedEventEmitter {
74
77
  content: { message: "Cannot submit signal with storage-only connection", code: 403 },
75
78
  });
76
79
  }
77
- get disposed() { return this._disposed; }
78
- dispose() { this._disposed = true; }
80
+ get disposed() {
81
+ return this._disposed;
82
+ }
83
+ dispose() {
84
+ this._disposed = true;
85
+ }
79
86
  }
87
+ const waitForOnline = async () => {
88
+ var _a;
89
+ // Only wait if we have a strong signal that we're offline - otherwise assume we're online.
90
+ if (((_a = globalThis.navigator) === null || _a === void 0 ? void 0 : _a.onLine) === false && globalThis.addEventListener !== undefined) {
91
+ return new Promise((resolve) => {
92
+ const resolveAndRemoveListener = () => {
93
+ resolve();
94
+ globalThis.removeEventListener("online", resolveAndRemoveListener);
95
+ };
96
+ globalThis.addEventListener("online", resolveAndRemoveListener);
97
+ });
98
+ }
99
+ };
80
100
  /**
81
101
  * Implementation of IConnectionManager, used by Container class
82
102
  * Implements constant connectivity to relay service, by reconnecting in case of lost connection or error.
@@ -94,12 +114,12 @@ class ConnectionManager {
94
114
  this.pendingReconnect = false;
95
115
  this.clientSequenceNumber = 0;
96
116
  this.clientSequenceNumberObserved = 0;
97
- /** Counts the number of noops sent by the client which may not be acked. */
117
+ /** Counts the number of non-runtime ops sent by the client which may not be acked. */
98
118
  this.localOpsToIgnore = 0;
99
119
  this.connectFirstConnection = true;
100
120
  this._connectionVerboseProps = {};
101
121
  this._connectionProps = {};
102
- this.closed = false;
122
+ this._disposed = false;
103
123
  this.opHandler = (documentId, messagesArg) => {
104
124
  const messages = Array.isArray(messagesArg) ? messagesArg : [messagesArg];
105
125
  this.props.incomingOpHandler(messages, "opHandler");
@@ -143,7 +163,9 @@ class ConnectionManager {
143
163
  this.props.closeHandler((0, telemetry_utils_1.normalizeError)(error));
144
164
  });
145
165
  }
146
- get connectionVerboseProps() { return this._connectionVerboseProps; }
166
+ get connectionVerboseProps() {
167
+ return this._connectionVerboseProps;
168
+ }
147
169
  /**
148
170
  * The current connection mode, initially read.
149
171
  */
@@ -151,8 +173,13 @@ class ConnectionManager {
151
173
  var _a, _b;
152
174
  return (_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : "read";
153
175
  }
154
- get connected() { return this.connection !== undefined; }
155
- get clientId() { var _a; return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.clientId; }
176
+ get connected() {
177
+ return this.connection !== undefined;
178
+ }
179
+ get clientId() {
180
+ var _a;
181
+ return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.clientId;
182
+ }
156
183
  /**
157
184
  * Automatic reconnecting enabled or disabled.
158
185
  * If set to Never, then reconnecting will never be allowed.
@@ -184,7 +211,7 @@ class ConnectionManager {
184
211
  /**
185
212
  * Returns set of props that can be logged in telemetry that provide some insights / statistics
186
213
  * about current or last connection (if there is no connection at the moment)
187
- */
214
+ */
188
215
  get connectionProps() {
189
216
  return this.connection !== undefined
190
217
  ? this._connectionProps
@@ -194,7 +221,7 @@ class ConnectionManager {
194
221
  }
195
222
  shouldJoinWrite() {
196
223
  // We don't have to wait for ack for topmost NoOps. So subtract those.
197
- return this.clientSequenceNumberObserved < (this.clientSequenceNumber - this.localOpsToIgnore);
224
+ return (this.clientSequenceNumberObserved < this.clientSequenceNumber - this.localOpsToIgnore);
198
225
  }
199
226
  /**
200
227
  * Tells if container is in read-only mode.
@@ -227,37 +254,38 @@ class ConnectionManager {
227
254
  return {
228
255
  claims: connection.claims,
229
256
  clientId: connection.clientId,
230
- existing: connection.existing,
231
257
  checkpointSequenceNumber: connection.checkpointSequenceNumber,
232
- get initialClients() { return connection.initialClients; },
258
+ get initialClients() {
259
+ return connection.initialClients;
260
+ },
233
261
  mode: connection.mode,
234
262
  serviceConfiguration: connection.serviceConfiguration,
235
263
  version: connection.version,
236
264
  };
237
265
  }
238
- dispose(error) {
239
- if (this.closed) {
266
+ dispose(error, switchToReadonly = true) {
267
+ if (this._disposed) {
240
268
  return;
241
269
  }
242
- this.closed = true;
270
+ this._disposed = true;
243
271
  this.pendingConnection = undefined;
244
272
  // Ensure that things like triggerConnect() will short circuit
245
273
  this._reconnectMode = contracts_1.ReconnectMode.Never;
246
274
  this._outbound.clear();
247
- const disconnectReason = error !== undefined
248
- ? `Closing DeltaManager (${error.message})`
249
- : "Closing DeltaManager";
275
+ const disconnectReason = "Closing DeltaManager";
250
276
  // This raises "disconnect" event if we have active connection.
251
277
  this.disconnectFromDeltaStream(disconnectReason);
252
- // Notify everyone we are in read-only state.
253
- // Useful for data stores in case we hit some critical error,
254
- // to switch to a mode where user edits are not accepted
255
- this.set_readonlyPermissions(true);
278
+ if (switchToReadonly) {
279
+ // Notify everyone we are in read-only state.
280
+ // Useful for data stores in case we hit some critical error,
281
+ // to switch to a mode where user edits are not accepted
282
+ this.set_readonlyPermissions(true);
283
+ }
256
284
  }
257
285
  /**
258
286
  * Enables or disables automatic reconnecting.
259
287
  * Will throw an error if reconnectMode set to Never.
260
- */
288
+ */
261
289
  setAutoReconnect(mode) {
262
290
  (0, common_utils_1.assert)(mode !== contracts_1.ReconnectMode.Never && this._reconnectMode !== contracts_1.ReconnectMode.Never, 0x278 /* "API is not supported for non-connecting or closed container" */);
263
291
  this._reconnectMode = mode;
@@ -329,8 +357,8 @@ class ConnectionManager {
329
357
  });
330
358
  }
331
359
  async connectCore(connectionMode) {
332
- var _a, _b;
333
- (0, common_utils_1.assert)(!this.closed, 0x26a /* "not closed" */);
360
+ var _a, _b, _c;
361
+ (0, common_utils_1.assert)(!this._disposed, 0x26a /* "not closed" */);
334
362
  if (this.connection !== undefined) {
335
363
  return; // Connection attempt already completed successfully
336
364
  }
@@ -365,10 +393,15 @@ class ConnectionManager {
365
393
  let lastError;
366
394
  const abortController = new abort_controller_1.default();
367
395
  const abortSignal = abortController.signal;
368
- this.pendingConnection = { abort: () => { abortController.abort(); }, connectionMode: requestedMode };
396
+ this.pendingConnection = {
397
+ abort: () => {
398
+ abortController.abort();
399
+ },
400
+ connectionMode: requestedMode,
401
+ };
369
402
  // This loop will keep trying to connect until successful, with a delay between each iteration.
370
403
  while (connection === undefined) {
371
- if (this.closed) {
404
+ if (this._disposed) {
372
405
  throw new Error("Attempting to connect a closed DeltaManager");
373
406
  }
374
407
  if (abortSignal.aborted === true) {
@@ -391,8 +424,9 @@ class ConnectionManager {
391
424
  }
392
425
  }
393
426
  catch (origError) {
394
- if (typeof origError === "object" && origError !== null &&
395
- (origError === null || origError === void 0 ? void 0 : origError.errorType) === driver_utils_1.DeltaStreamConnectionForbiddenError.errorType) {
427
+ if (typeof origError === "object" &&
428
+ origError !== null &&
429
+ (origError === null || origError === void 0 ? void 0 : origError.errorType) === driver_definitions_1.DriverErrorType.deltaStreamConnectionForbidden) {
396
430
  connection = new NoDeltaStream();
397
431
  requestedMode = "read";
398
432
  break;
@@ -412,11 +446,25 @@ class ConnectionManager {
412
446
  }, origError);
413
447
  lastError = origError;
414
448
  const retryDelayFromError = (0, driver_utils_1.getRetryDelayFromError)(origError);
415
- delayMs = retryDelayFromError !== null && retryDelayFromError !== void 0 ? retryDelayFromError : Math.min(delayMs * 2, MaxReconnectDelayInMs);
416
449
  if (retryDelayFromError !== undefined) {
450
+ // If the error told us to wait, then we wait.
417
451
  this.props.reconnectionDelayHandler(retryDelayFromError, origError);
452
+ await new Promise((resolve) => {
453
+ setTimeout(resolve, retryDelayFromError);
454
+ });
455
+ }
456
+ else if (((_c = globalThis.navigator) === null || _c === void 0 ? void 0 : _c.onLine) !== false) {
457
+ // If the error didn't tell us to wait, let's still wait a little bit before retrying.
458
+ // We skip this delay if we're confident we're offline, because we probably just need to wait to come back online.
459
+ await new Promise((resolve) => {
460
+ setTimeout(resolve, delayMs);
461
+ delayMs = Math.min(delayMs * 2, MaxReconnectDelayInMs);
462
+ });
418
463
  }
419
- await (0, driver_utils_1.waitForConnectedState)(delayMs);
464
+ // If we believe we're offline, we assume there's no point in trying until we at least think we're online.
465
+ // NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
466
+ // should probably live in the driver.
467
+ await waitForOnline();
420
468
  }
421
469
  }
422
470
  // If we retried more than once, log an event about how long it took (this will not log to error table)
@@ -446,7 +494,7 @@ class ConnectionManager {
446
494
  * @param args - The connection arguments
447
495
  */
448
496
  triggerConnect(connectionMode) {
449
- // reconnect() has async await of waitForConnectedState(), and that causes potential race conditions
497
+ // reconnect() includes async awaits, and that causes potential race conditions
450
498
  // where we might already have a connection. If it were to happen, it's possible that we will connect
451
499
  // with different mode to `connectionMode`. Glancing through the caller chains, it looks like code should be
452
500
  // fine (if needed, reconnect flow will get triggered again). Places where new mode matters should encode it
@@ -485,8 +533,8 @@ class ConnectionManager {
485
533
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
486
534
  this._outbound.pause();
487
535
  this._outbound.clear();
488
- this.props.disconnectHandler(reason);
489
536
  connection.dispose();
537
+ this.props.disconnectHandler(reason);
490
538
  this._connectionVerboseProps = {};
491
539
  return true;
492
540
  }
@@ -516,14 +564,18 @@ class ConnectionManager {
516
564
  // But if we ask read, server can still give us write.
517
565
  const readonly = !connection.claims.scopes.includes(protocol_definitions_1.ScopeType.DocWrite);
518
566
  if (connection.mode !== requestedMode) {
519
- this.logger.sendTelemetryEvent({ eventName: "ConnectionModeMismatch", requestedMode, mode: connection.mode });
567
+ this.logger.sendTelemetryEvent({
568
+ eventName: "ConnectionModeMismatch",
569
+ requestedMode,
570
+ mode: connection.mode,
571
+ });
520
572
  }
521
573
  // This connection mode validation logic is moving to the driver layer in 0.44. These two asserts can be
522
574
  // removed after those packages have released and become ubiquitous.
523
575
  (0, common_utils_1.assert)(requestedMode === "read" || readonly === (this.connectionMode === "read"), 0x0e7 /* "claims/connectionMode mismatch" */);
524
576
  (0, common_utils_1.assert)(!readonly || this.connectionMode === "read", 0x0e8 /* "readonly perf with write connection" */);
525
577
  this.set_readonlyPermissions(readonly);
526
- if (this.closed) {
578
+ if (this._disposed) {
527
579
  // Raise proper events, Log telemetry event and close connection.
528
580
  this.disconnectFromDeltaStream("ConnectionManager already closed");
529
581
  return;
@@ -556,7 +608,8 @@ class ConnectionManager {
556
608
  this._connectionProps.connectionMode = connection.mode;
557
609
  let last = -1;
558
610
  if (initialMessages.length !== 0) {
559
- this._connectionVerboseProps.connectionInitialOpsFrom = initialMessages[0].sequenceNumber;
611
+ this._connectionVerboseProps.connectionInitialOpsFrom =
612
+ initialMessages[0].sequenceNumber;
560
613
  last = initialMessages[initialMessages.length - 1].sequenceNumber;
561
614
  this._connectionVerboseProps.connectionInitialOpsTo = last + 1;
562
615
  // Update knowledge of how far we are behind, before raising "connect" event
@@ -609,8 +662,7 @@ class ConnectionManager {
609
662
  * @returns A promise that resolves when the connection is reestablished or we stop trying
610
663
  */
611
664
  reconnectOnError(requestedMode, error) {
612
- this.reconnect(requestedMode, error.message, error)
613
- .catch(this.props.closeHandler);
665
+ this.reconnect(requestedMode, error.message, error).catch(this.props.closeHandler);
614
666
  }
615
667
  /**
616
668
  * Disconnect the current connection and reconnect.
@@ -641,14 +693,21 @@ class ConnectionManager {
641
693
  this.props.closeHandler();
642
694
  }
643
695
  // If closed then we can't reconnect
644
- if (this.closed || this.reconnectMode !== contracts_1.ReconnectMode.Enabled) {
696
+ if (this._disposed || this.reconnectMode !== contracts_1.ReconnectMode.Enabled) {
645
697
  return;
646
698
  }
699
+ // If the error tells us to wait before retrying, then do so.
647
700
  const delayMs = (0, driver_utils_1.getRetryDelayFromError)(error);
648
701
  if (error !== undefined && delayMs !== undefined) {
649
702
  this.props.reconnectionDelayHandler(delayMs, error);
650
- await (0, driver_utils_1.waitForConnectedState)(delayMs);
703
+ await new Promise((resolve) => {
704
+ setTimeout(resolve, delayMs);
705
+ });
651
706
  }
707
+ // If we believe we're offline, we assume there's no point in trying again until we at least think we're online.
708
+ // NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
709
+ // should probably live in the driver.
710
+ await waitForOnline();
652
711
  this.triggerConnect(requestedMode);
653
712
  }
654
713
  prepareMessageToSend(message) {
@@ -700,12 +759,15 @@ class ConnectionManager {
700
759
  if (this.connectionMode === "read") {
701
760
  if (!this.pendingReconnect) {
702
761
  this.pendingReconnect = true;
703
- Promise.resolve().then(async () => {
704
- if (this.pendingReconnect) { // still valid?
762
+ Promise.resolve()
763
+ .then(async () => {
764
+ if (this.pendingReconnect) {
765
+ // still valid?
705
766
  await this.reconnect("write", // connectionMode
706
767
  "Switch to write");
707
768
  }
708
- }).catch(() => { });
769
+ })
770
+ .catch(() => { });
709
771
  }
710
772
  return;
711
773
  }
@@ -715,7 +777,8 @@ class ConnectionManager {
715
777
  beforeProcessingIncomingOp(message) {
716
778
  // if we have connection, and message is local, then we better treat is as local!
717
779
  (0, common_utils_1.assert)(this.clientId !== message.clientId || this.lastSubmittedClientId === message.clientId, 0x0ee /* "Not accounting local messages correctly" */);
718
- if (this.lastSubmittedClientId !== undefined && this.lastSubmittedClientId === message.clientId) {
780
+ if (this.lastSubmittedClientId !== undefined &&
781
+ this.lastSubmittedClientId === message.clientId) {
719
782
  const clientSequenceNumber = message.clientSequenceNumber;
720
783
  (0, common_utils_1.assert)(this.clientSequenceNumberObserved < clientSequenceNumber, 0x0ef /* "client seq# not growing" */);
721
784
  (0, common_utils_1.assert)(clientSequenceNumber <= this.clientSequenceNumber, 0x0f0 /* "Incoming local client seq# > generated by this client" */);