@fluidframework/container-loader 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191258

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 (173) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/README.md +10 -6
  3. package/dist/audience.d.ts +1 -0
  4. package/dist/audience.d.ts.map +1 -1
  5. package/dist/audience.js +5 -3
  6. package/dist/audience.js.map +1 -1
  7. package/dist/catchUpMonitor.js +2 -2
  8. package/dist/catchUpMonitor.js.map +1 -1
  9. package/dist/connectionManager.d.ts +5 -5
  10. package/dist/connectionManager.d.ts.map +1 -1
  11. package/dist/connectionManager.js +97 -93
  12. package/dist/connectionManager.js.map +1 -1
  13. package/dist/connectionStateHandler.d.ts +15 -14
  14. package/dist/connectionStateHandler.d.ts.map +1 -1
  15. package/dist/connectionStateHandler.js +50 -52
  16. package/dist/connectionStateHandler.js.map +1 -1
  17. package/dist/container.d.ts +20 -9
  18. package/dist/container.d.ts.map +1 -1
  19. package/dist/container.js +327 -277
  20. package/dist/container.js.map +1 -1
  21. package/dist/containerContext.d.ts +2 -7
  22. package/dist/containerContext.d.ts.map +1 -1
  23. package/dist/containerContext.js +2 -14
  24. package/dist/containerContext.js.map +1 -1
  25. package/dist/containerStorageAdapter.d.ts.map +1 -1
  26. package/dist/containerStorageAdapter.js +12 -13
  27. package/dist/containerStorageAdapter.js.map +1 -1
  28. package/dist/contracts.d.ts +21 -8
  29. package/dist/contracts.d.ts.map +1 -1
  30. package/dist/contracts.js +3 -3
  31. package/dist/contracts.js.map +1 -1
  32. package/dist/debugLogger.d.ts +30 -0
  33. package/dist/debugLogger.d.ts.map +1 -0
  34. package/dist/debugLogger.js +95 -0
  35. package/dist/debugLogger.js.map +1 -0
  36. package/dist/deltaManager.d.ts +21 -10
  37. package/dist/deltaManager.d.ts.map +1 -1
  38. package/dist/deltaManager.js +114 -66
  39. package/dist/deltaManager.js.map +1 -1
  40. package/dist/deltaQueue.d.ts +1 -1
  41. package/dist/deltaQueue.d.ts.map +1 -1
  42. package/dist/deltaQueue.js +10 -10
  43. package/dist/deltaQueue.js.map +1 -1
  44. package/dist/disposal.d.ts +2 -2
  45. package/dist/disposal.d.ts.map +1 -1
  46. package/dist/disposal.js +1 -1
  47. package/dist/disposal.js.map +1 -1
  48. package/dist/error.d.ts +23 -0
  49. package/dist/error.d.ts.map +1 -0
  50. package/dist/error.js +32 -0
  51. package/dist/error.js.map +1 -0
  52. package/dist/loader.d.ts +22 -3
  53. package/dist/loader.d.ts.map +1 -1
  54. package/dist/loader.js +82 -51
  55. package/dist/loader.js.map +1 -1
  56. package/dist/noopHeuristic.d.ts +2 -2
  57. package/dist/noopHeuristic.d.ts.map +1 -1
  58. package/dist/noopHeuristic.js +6 -5
  59. package/dist/noopHeuristic.js.map +1 -1
  60. package/dist/packageVersion.d.ts +1 -1
  61. package/dist/packageVersion.js +1 -1
  62. package/dist/packageVersion.js.map +1 -1
  63. package/dist/protocol.d.ts +4 -2
  64. package/dist/protocol.d.ts.map +1 -1
  65. package/dist/protocol.js +25 -4
  66. package/dist/protocol.js.map +1 -1
  67. package/dist/quorum.d.ts +4 -1
  68. package/dist/quorum.d.ts.map +1 -1
  69. package/dist/quorum.js +1 -13
  70. package/dist/quorum.js.map +1 -1
  71. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  72. package/dist/retriableDocumentStorageService.js +4 -4
  73. package/dist/retriableDocumentStorageService.js.map +1 -1
  74. package/dist/utils.d.ts +8 -1
  75. package/dist/utils.d.ts.map +1 -1
  76. package/dist/utils.js +30 -11
  77. package/dist/utils.js.map +1 -1
  78. package/lib/audience.d.ts +1 -0
  79. package/lib/audience.d.ts.map +1 -1
  80. package/lib/audience.js +4 -2
  81. package/lib/audience.js.map +1 -1
  82. package/lib/catchUpMonitor.js +1 -1
  83. package/lib/catchUpMonitor.js.map +1 -1
  84. package/lib/connectionManager.d.ts +5 -5
  85. package/lib/connectionManager.d.ts.map +1 -1
  86. package/lib/connectionManager.js +74 -67
  87. package/lib/connectionManager.js.map +1 -1
  88. package/lib/connectionStateHandler.d.ts +15 -14
  89. package/lib/connectionStateHandler.d.ts.map +1 -1
  90. package/lib/connectionStateHandler.js +27 -29
  91. package/lib/connectionStateHandler.js.map +1 -1
  92. package/lib/container.d.ts +20 -9
  93. package/lib/container.d.ts.map +1 -1
  94. package/lib/container.js +288 -238
  95. package/lib/container.js.map +1 -1
  96. package/lib/containerContext.d.ts +2 -7
  97. package/lib/containerContext.d.ts.map +1 -1
  98. package/lib/containerContext.js +2 -14
  99. package/lib/containerContext.js.map +1 -1
  100. package/lib/containerStorageAdapter.d.ts.map +1 -1
  101. package/lib/containerStorageAdapter.js +5 -6
  102. package/lib/containerStorageAdapter.js.map +1 -1
  103. package/lib/contracts.d.ts +21 -8
  104. package/lib/contracts.d.ts.map +1 -1
  105. package/lib/contracts.js +3 -3
  106. package/lib/contracts.js.map +1 -1
  107. package/lib/debugLogger.d.ts +30 -0
  108. package/lib/debugLogger.d.ts.map +1 -0
  109. package/lib/debugLogger.js +91 -0
  110. package/lib/debugLogger.js.map +1 -0
  111. package/lib/deltaManager.d.ts +21 -10
  112. package/lib/deltaManager.d.ts.map +1 -1
  113. package/lib/deltaManager.js +88 -37
  114. package/lib/deltaManager.js.map +1 -1
  115. package/lib/deltaQueue.d.ts +1 -1
  116. package/lib/deltaQueue.d.ts.map +1 -1
  117. package/lib/deltaQueue.js +3 -3
  118. package/lib/deltaQueue.js.map +1 -1
  119. package/lib/disposal.d.ts +2 -2
  120. package/lib/disposal.d.ts.map +1 -1
  121. package/lib/disposal.js +1 -1
  122. package/lib/disposal.js.map +1 -1
  123. package/lib/error.d.ts +23 -0
  124. package/lib/error.d.ts.map +1 -0
  125. package/lib/error.js +28 -0
  126. package/lib/error.js.map +1 -0
  127. package/lib/loader.d.ts +22 -3
  128. package/lib/loader.d.ts.map +1 -1
  129. package/lib/loader.js +82 -51
  130. package/lib/loader.js.map +1 -1
  131. package/lib/noopHeuristic.d.ts +2 -2
  132. package/lib/noopHeuristic.d.ts.map +1 -1
  133. package/lib/noopHeuristic.js +2 -1
  134. package/lib/noopHeuristic.js.map +1 -1
  135. package/lib/packageVersion.d.ts +1 -1
  136. package/lib/packageVersion.js +1 -1
  137. package/lib/packageVersion.js.map +1 -1
  138. package/lib/protocol.d.ts +4 -2
  139. package/lib/protocol.d.ts.map +1 -1
  140. package/lib/protocol.js +25 -4
  141. package/lib/protocol.js.map +1 -1
  142. package/lib/quorum.d.ts +4 -1
  143. package/lib/quorum.d.ts.map +1 -1
  144. package/lib/quorum.js +0 -11
  145. package/lib/quorum.js.map +1 -1
  146. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  147. package/lib/retriableDocumentStorageService.js +2 -2
  148. package/lib/retriableDocumentStorageService.js.map +1 -1
  149. package/lib/utils.d.ts +8 -1
  150. package/lib/utils.d.ts.map +1 -1
  151. package/lib/utils.js +25 -7
  152. package/lib/utils.js.map +1 -1
  153. package/package.json +26 -32
  154. package/src/audience.ts +7 -1
  155. package/src/catchUpMonitor.ts +1 -1
  156. package/src/connectionManager.ts +75 -51
  157. package/src/connectionStateHandler.ts +31 -38
  158. package/src/container.ts +335 -240
  159. package/src/containerContext.ts +0 -16
  160. package/src/containerStorageAdapter.ts +2 -1
  161. package/src/contracts.ts +27 -11
  162. package/src/debugLogger.ts +113 -0
  163. package/src/deltaManager.ts +84 -34
  164. package/src/deltaQueue.ts +2 -1
  165. package/src/disposal.ts +2 -2
  166. package/src/error.ts +44 -0
  167. package/src/loader.ts +83 -35
  168. package/src/noopHeuristic.ts +3 -2
  169. package/src/packageVersion.ts +1 -1
  170. package/src/protocol.ts +33 -2
  171. package/src/quorum.ts +0 -10
  172. package/src/retriableDocumentStorageService.ts +2 -4
  173. package/src/utils.ts +33 -8
@@ -18,7 +18,6 @@ import {
18
18
  import { FluidObject } from "@fluidframework/core-interfaces";
19
19
  import { IDocumentStorageService } from "@fluidframework/driver-definitions";
20
20
  import {
21
- IClientConfiguration,
22
21
  IClientDetails,
23
22
  IDocumentMessage,
24
23
  IQuorumClients,
@@ -61,16 +60,6 @@ export class ContainerContext implements IContainerContext {
61
60
  return this._getConnected();
62
61
  }
63
62
 
64
- public get serviceConfiguration(): IClientConfiguration | undefined {
65
- return this._getServiceConfiguration();
66
- }
67
-
68
- private _disposed = false;
69
-
70
- public get disposed() {
71
- return this._disposed;
72
- }
73
-
74
63
  constructor(
75
64
  public readonly options: ILoaderOptions,
76
65
  public readonly scope: FluidObject,
@@ -103,7 +92,6 @@ export class ContainerContext implements IContainerContext {
103
92
  public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>,
104
93
  private readonly _getContainerDiagnosticId: () => string | undefined,
105
94
  private readonly _getClientId: () => string | undefined,
106
- private readonly _getServiceConfiguration: () => IClientConfiguration | undefined,
107
95
  private readonly _getAttachState: () => AttachState,
108
96
  private readonly _getConnected: () => boolean,
109
97
  public readonly getSpecifiedCodeDetails: () => IFluidCodeDetails | undefined,
@@ -113,10 +101,6 @@ export class ContainerContext implements IContainerContext {
113
101
  public readonly pendingLocalState?: unknown,
114
102
  ) {}
115
103
 
116
- public dispose(error?: Error): void {
117
- this._disposed = true;
118
- }
119
-
120
104
  public getLoadedFromVersion(): IVersion | undefined {
121
105
  return this._version;
122
106
  }
@@ -5,7 +5,8 @@
5
5
 
6
6
  import { IDisposable } from "@fluidframework/core-interfaces";
7
7
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
8
- import { assert, bufferToString, stringToBuffer } from "@fluidframework/common-utils";
8
+ import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
9
+ import { assert } from "@fluidframework/core-utils";
9
10
  import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
10
11
  import {
11
12
  FetchSource,
package/src/contracts.ts CHANGED
@@ -3,24 +3,25 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryProperties } from "@fluidframework/core-interfaces";
6
+ import { IErrorBase, ITelemetryProperties } from "@fluidframework/core-interfaces";
7
7
  import {
8
- IDeltaQueue,
9
- ReadOnlyInfo,
10
- IConnectionDetailsInternal,
8
+ IConnectionDetails,
11
9
  ICriticalContainerError,
10
+ IDeltaQueue,
12
11
  IFluidCodeDetails,
13
12
  isFluidPackage,
13
+ ReadOnlyInfo,
14
14
  } from "@fluidframework/container-definitions";
15
15
  import {
16
16
  ConnectionMode,
17
- IDocumentMessage,
18
- ISequencedDocumentMessage,
19
17
  IClientConfiguration,
20
18
  IClientDetails,
19
+ IDocumentMessage,
20
+ ISequencedDocumentMessage,
21
+ ISignalClient,
21
22
  ISignalMessage,
22
23
  } from "@fluidframework/protocol-definitions";
23
- import { IAnyDriverError, IContainerPackageInfo } from "@fluidframework/driver-definitions";
24
+ import { IContainerPackageInfo } from "@fluidframework/driver-definitions";
24
25
 
25
26
  export enum ReconnectMode {
26
27
  Never = "Never",
@@ -28,6 +29,21 @@ export enum ReconnectMode {
28
29
  Enabled = "Enabled",
29
30
  }
30
31
 
32
+ export interface IConnectionStateChangeReason<T extends IErrorBase = IErrorBase> {
33
+ text: string;
34
+ error?: T;
35
+ }
36
+
37
+ /**
38
+ * Internal version of IConnectionDetails with props are only exposed internally
39
+ */
40
+ export interface IConnectionDetailsInternal extends IConnectionDetails {
41
+ mode: ConnectionMode;
42
+ version: string;
43
+ initialClients: ISignalClient[];
44
+ reason: IConnectionStateChangeReason;
45
+ }
46
+
31
47
  /**
32
48
  * Connection manager (implements this interface) is responsible for maintaining connection
33
49
  * to relay service.
@@ -95,7 +111,7 @@ export interface IConnectionManager {
95
111
  /**
96
112
  * Initiates connection to relay service (noop if already connected).
97
113
  */
98
- connect(reason: string, connectionMode?: ConnectionMode): void;
114
+ connect(reason: IConnectionStateChangeReason, connectionMode?: ConnectionMode): void;
99
115
 
100
116
  /**
101
117
  * Disposed connection manager
@@ -139,7 +155,7 @@ export interface IConnectionManagerFactoryArgs {
139
155
  /**
140
156
  * Called whenever connection to relay service is lost.
141
157
  */
142
- readonly disconnectHandler: (reason: string, error?: IAnyDriverError) => void;
158
+ readonly disconnectHandler: (reason: IConnectionStateChangeReason) => void;
143
159
 
144
160
  /**
145
161
  * Called whenever new connection to rely service is established
@@ -169,12 +185,12 @@ export interface IConnectionManagerFactoryArgs {
169
185
  /**
170
186
  * Called whenever we try to start establishing a new connection.
171
187
  */
172
- readonly establishConnectionHandler: (reason: string) => void;
188
+ readonly establishConnectionHandler: (reason: IConnectionStateChangeReason) => void;
173
189
 
174
190
  /**
175
191
  * Called whenever we cancel the connection in progress.
176
192
  */
177
- readonly cancelConnectionHandler: (reason: string) => void;
193
+ readonly cancelConnectionHandler: (reason: IConnectionStateChangeReason) => void;
178
194
  }
179
195
 
180
196
  /**
@@ -0,0 +1,113 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import {
7
+ ITelemetryBaseEvent,
8
+ ITelemetryBaseLogger,
9
+ ITelemetryProperties,
10
+ } from "@fluidframework/core-interfaces";
11
+ import { performance } from "@fluid-internal/client-utils";
12
+ import { debug as registerDebug, IDebugger } from "debug";
13
+ import {
14
+ ITelemetryLoggerExt,
15
+ ITelemetryLoggerPropertyBags,
16
+ createMultiSinkLogger,
17
+ eventNamespaceSeparator,
18
+ formatTick,
19
+ } from "@fluidframework/telemetry-utils";
20
+
21
+ /**
22
+ * Implementation of debug logger
23
+ */
24
+ export class DebugLogger implements ITelemetryBaseLogger {
25
+ /**
26
+ * Mix in debug logger with another logger.
27
+ * Returned logger will output events to both newly created debug logger, as well as base logger
28
+ * @param namespace - Telemetry event name prefix to add to all events
29
+ * @param properties - Base properties to add to all events
30
+ * @param propertyGetters - Getters to add additional properties to all events
31
+ * @param baseLogger - Base logger to output events (in addition to debug logger being created). Can be undefined.
32
+ */
33
+ public static mixinDebugLogger(
34
+ namespace: string,
35
+ baseLogger?: ITelemetryBaseLogger,
36
+ properties?: ITelemetryLoggerPropertyBags,
37
+ ): ITelemetryLoggerExt {
38
+ // Setup base logger upfront, such that host can disable it (if needed)
39
+ const debug = registerDebug(namespace);
40
+
41
+ // Create one for errors that is always enabled
42
+ // It can be silenced by replacing console.error if the debug namespace is not enabled.
43
+ const debugErr = registerDebug(namespace);
44
+ debugErr.log = function (...args) {
45
+ if (debug.enabled === true) {
46
+ // if the namespace is enabled, just use the default logger
47
+ registerDebug.log(...args);
48
+ } else {
49
+ // other wise, use the console logger (which could be replaced and silenced)
50
+ console.error(...args);
51
+ }
52
+ };
53
+ debugErr.enabled = true;
54
+
55
+ return createMultiSinkLogger({
56
+ namespace,
57
+ loggers: [baseLogger, new DebugLogger(debug, debugErr)],
58
+ properties,
59
+ tryInheritProperties: true,
60
+ });
61
+ }
62
+
63
+ private constructor(private readonly debug: IDebugger, private readonly debugErr: IDebugger) {}
64
+
65
+ /**
66
+ * Send an event to debug loggers
67
+ *
68
+ * @param event - the event to send
69
+ */
70
+ public send(event: ITelemetryBaseEvent): void {
71
+ const newEvent: ITelemetryProperties = { ...event };
72
+ const isError = newEvent.category === "error";
73
+ let logger = isError ? this.debugErr : this.debug;
74
+
75
+ // Use debug's coloring schema for base of the event
76
+ const index = event.eventName.lastIndexOf(eventNamespaceSeparator);
77
+ const name = event.eventName.substring(index + 1);
78
+ if (index > 0) {
79
+ logger = logger.extend(event.eventName.substring(0, index));
80
+ }
81
+ newEvent.eventName = undefined;
82
+
83
+ let tick = "";
84
+ tick = `tick=${formatTick(performance.now())}`;
85
+
86
+ // Extract stack to put it last, but also to avoid escaping '\n' in it by JSON.stringify below
87
+ const stack = newEvent.stack ?? "";
88
+ newEvent.stack = undefined;
89
+
90
+ // Watch out for circular references - they can come from two sources
91
+ // 1) error object - we do not control it and should remove it and retry
92
+ // 2) properties supplied by telemetry caller - that's a bug that should be addressed!
93
+ let payload: string;
94
+ try {
95
+ payload = JSON.stringify(newEvent);
96
+ } catch (error) {
97
+ newEvent.error = undefined;
98
+ payload = JSON.stringify(newEvent);
99
+ }
100
+
101
+ if (payload === "{}") {
102
+ payload = "";
103
+ }
104
+
105
+ // Force errors out, to help with diagnostics
106
+ if (isError) {
107
+ logger.enabled = true;
108
+ }
109
+
110
+ // Print multi-line.
111
+ logger(`${name} ${payload} ${tick} ${stack}`);
112
+ }
113
+ }
@@ -3,32 +3,36 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { default as AbortController } from "abort-controller";
7
6
  import { v4 as uuid } from "uuid";
8
- import { IEventProvider } from "@fluidframework/common-definitions";
9
- import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
10
7
  import {
11
- IDeltaHandlerStrategy,
8
+ IThrottlingWarning,
9
+ IEventProvider,
10
+ ITelemetryProperties,
11
+ ITelemetryErrorEvent,
12
+ } from "@fluidframework/core-interfaces";
13
+ import {
14
+ ICriticalContainerError,
12
15
  IDeltaManager,
13
16
  IDeltaManagerEvents,
14
17
  IDeltaQueue,
15
- ICriticalContainerError,
16
- IThrottlingWarning,
17
- IConnectionDetailsInternal,
18
18
  } from "@fluidframework/container-definitions";
19
- import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
19
+ import { TypedEventEmitter } from "@fluid-internal/client-utils";
20
+ import { assert } from "@fluidframework/core-utils";
20
21
  import {
22
+ DataProcessingError,
23
+ extractSafePropertiesFromMessage,
21
24
  normalizeError,
22
25
  logIfFalse,
23
26
  safeRaiseEvent,
24
27
  isFluidError,
25
28
  ITelemetryLoggerExt,
29
+ DataCorruptionError,
30
+ UsageError,
26
31
  } from "@fluidframework/telemetry-utils";
27
32
  import {
28
33
  IDocumentDeltaStorageService,
29
34
  IDocumentService,
30
- DriverErrorType,
31
- IAnyDriverError,
35
+ DriverErrorTypes,
32
36
  } from "@fluidframework/driver-definitions";
33
37
  import {
34
38
  IDocumentMessage,
@@ -38,21 +42,21 @@ import {
38
42
  ConnectionMode,
39
43
  } from "@fluidframework/protocol-definitions";
40
44
  import { NonRetryableError, isRuntimeMessage, MessageType2 } from "@fluidframework/driver-utils";
45
+
41
46
  import {
42
- ThrottlingWarning,
43
- DataCorruptionError,
44
- extractSafePropertiesFromMessage,
45
- DataProcessingError,
46
- UsageError,
47
- } from "@fluidframework/container-utils";
48
- import { IConnectionManagerFactoryArgs, IConnectionManager } from "./contracts";
47
+ IConnectionDetailsInternal,
48
+ IConnectionManager,
49
+ IConnectionManagerFactoryArgs,
50
+ IConnectionStateChangeReason,
51
+ } from "./contracts";
49
52
  import { DeltaQueue } from "./deltaQueue";
50
53
  import { OnlyValidTermValue } from "./protocol";
54
+ import { ThrottlingWarning } from "./error";
51
55
 
52
56
  export interface IConnectionArgs {
53
57
  mode?: ConnectionMode;
54
58
  fetchOpsFromStorage?: boolean;
55
- reason: string;
59
+ reason: IConnectionStateChangeReason;
56
60
  }
57
61
 
58
62
  /**
@@ -63,8 +67,11 @@ export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
63
67
  (event: "throttled", listener: (error: IThrottlingWarning) => void);
64
68
  (event: "closed" | "disposed", listener: (error?: ICriticalContainerError) => void);
65
69
  (event: "connect", listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void);
66
- (event: "establishingConnection", listener: (reason: string) => void);
67
- (event: "cancelEstablishingConnection", listener: (reason: string) => void);
70
+ (event: "establishingConnection", listener: (reason: IConnectionStateChangeReason) => void);
71
+ (
72
+ event: "cancelEstablishingConnection",
73
+ listener: (reason: IConnectionStateChangeReason) => void,
74
+ );
68
75
  }
69
76
 
70
77
  /**
@@ -74,6 +81,21 @@ interface IBatchMetadata {
74
81
  batch?: boolean;
75
82
  }
76
83
 
84
+ /**
85
+ * Interface used to define a strategy for handling incoming delta messages
86
+ */
87
+ export interface IDeltaHandlerStrategy {
88
+ /**
89
+ * Processes the message.
90
+ */
91
+ process: (message: ISequencedDocumentMessage) => void;
92
+
93
+ /**
94
+ * Processes the signal.
95
+ */
96
+ processSignal: (message: ISignalMessage) => void;
97
+ }
98
+
77
99
  /**
78
100
  * Determines if message was sent by client, not service
79
101
  */
@@ -93,6 +115,17 @@ function isClientMessage(message: ISequencedDocumentMessage | IDocumentMessage):
93
115
  }
94
116
  }
95
117
 
118
+ /**
119
+ * Type is used to cast AbortController to represent new version of DOM API and prevent build issues
120
+ * TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
121
+ */
122
+ type AbortControllerReal = AbortController & { abort(reason?: any): void };
123
+ /**
124
+ * Type is used to cast AbortSignal to represent new version of DOM API and prevent build issues
125
+ * TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
126
+ */
127
+ type AbortSignalReal = AbortSignal & { reason: any };
128
+
96
129
  /**
97
130
  * Manages the flow of both inbound and outbound messages. This class ensures that shared objects receive delta
98
131
  * messages in order regardless of possible network conditions or timings causing out of order delivery.
@@ -320,6 +353,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
320
353
  return {
321
354
  sequenceNumber: this.lastSequenceNumber,
322
355
  opsSize: this.opsSize > 0 ? this.opsSize : undefined,
356
+ deltaManagerState: this._disposed ? "disposed" : this._closed ? "closed" : "open",
323
357
  ...this.connectionManager.connectionProps,
324
358
  };
325
359
  }
@@ -373,15 +407,17 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
373
407
  reconnectionDelayHandler: (delayMs: number, error: unknown) =>
374
408
  this.emitDelayInfo(this.deltaStreamDelayId, delayMs, error),
375
409
  closeHandler: (error: any) => this.close(error),
376
- disconnectHandler: (reason: string, error?: IAnyDriverError) =>
377
- this.disconnectHandler(reason, error),
410
+ disconnectHandler: (reason: IConnectionStateChangeReason) =>
411
+ this.disconnectHandler(reason),
378
412
  connectHandler: (connection: IConnectionDetailsInternal) =>
379
413
  this.connectHandler(connection),
380
414
  pongHandler: (latency: number) => this.emit("pong", latency),
381
415
  readonlyChangeHandler: (readonly?: boolean) =>
382
416
  safeRaiseEvent(this, this.logger, "readonly", readonly),
383
- establishConnectionHandler: (reason: string) => this.establishingConnection(reason),
384
- cancelConnectionHandler: (reason: string) => this.cancelEstablishingConnection(reason),
417
+ establishConnectionHandler: (reason: IConnectionStateChangeReason) =>
418
+ this.establishingConnection(reason),
419
+ cancelConnectionHandler: (reason: IConnectionStateChangeReason) =>
420
+ this.cancelEstablishingConnection(reason),
385
421
  };
386
422
 
387
423
  this.connectionManager = createConnectionManager(props);
@@ -421,11 +457,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
421
457
  // - inbound & inboundSignal are resumed in attachOpHandler() when we have handler setup
422
458
  }
423
459
 
424
- private cancelEstablishingConnection(reason: string) {
460
+ private cancelEstablishingConnection(reason: IConnectionStateChangeReason) {
425
461
  this.emit("cancelEstablishingConnection", reason);
426
462
  }
427
463
 
428
- private establishingConnection(reason: string) {
464
+ private establishingConnection(reason: IConnectionStateChangeReason) {
429
465
  this.emit("establishingConnection", reason);
430
466
  }
431
467
 
@@ -485,7 +521,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
485
521
  minSequenceNumber: number,
486
522
  sequenceNumber: number,
487
523
  handler: IDeltaHandlerStrategy,
488
- prefetchType: "cached" | "all" | "none" = "none",
524
+ prefetchType: "sequenceNumber" | "cached" | "all" | "none" = "none",
489
525
  ) {
490
526
  this.initSequenceNumber = sequenceNumber;
491
527
  this.lastProcessedSequenceNumber = sequenceNumber;
@@ -559,7 +595,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
559
595
  // on the wire, we might be always behind.
560
596
  // See comment at the end of "connect" handler
561
597
  if (fetchOpsFromStorage) {
562
- this.fetchMissingDeltas(args.reason);
598
+ this.fetchMissingDeltas(args.reason.text);
563
599
  }
564
600
 
565
601
  this.connectionManager.connect(args.reason, args.mode);
@@ -624,7 +660,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
624
660
  // This is useless for known ranges (to is defined) as it means request is over either way.
625
661
  // And it will cancel unbound request too early, not allowing us to learn where the end of the file is.
626
662
  if (!opsFromFetch && cancelFetch(op)) {
627
- controller.abort();
663
+ // TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
664
+ (controller as AbortControllerReal).abort("DeltaManager getDeltas fetch cancelled");
628
665
  this._inbound.off("push", opListener);
629
666
  }
630
667
  };
@@ -632,7 +669,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
632
669
  try {
633
670
  this._inbound.on("push", opListener);
634
671
  assert(this.closeAbortController.signal.onabort === null, 0x1e8 /* "reentrancy" */);
635
- this.closeAbortController.signal.onabort = () => controller.abort();
672
+ this.closeAbortController.signal.onabort = () =>
673
+ // TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
674
+ (controller as AbortControllerReal).abort(
675
+ (this.closeAbortController.signal as AbortSignalReal).reason,
676
+ );
636
677
 
637
678
  const stream = this.deltaStorage.fetchMessages(
638
679
  from, // inclusive
@@ -656,6 +697,14 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
656
697
  }
657
698
  }
658
699
  } finally {
700
+ if (controller.signal.aborted) {
701
+ this.logger.sendTelemetryEvent({
702
+ eventName: "DeltaManager_GetDeltasAborted",
703
+ fetchReason,
704
+ // TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
705
+ reason: (controller.signal as AbortSignalReal).reason,
706
+ });
707
+ }
659
708
  this.closeAbortController.signal.onabort = null;
660
709
  this._inbound.off("push", opListener);
661
710
  assert(!opsFromFetch, 0x289 /* "logic error" */);
@@ -710,7 +759,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
710
759
  }
711
760
 
712
761
  private clearQueues() {
713
- this.closeAbortController.abort();
762
+ // TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
763
+ (this.closeAbortController as AbortControllerReal).abort("DeltaManager is closed");
714
764
 
715
765
  this._inbound.clear();
716
766
  this._inboundSignal.clear();
@@ -731,9 +781,9 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
731
781
  }
732
782
  }
733
783
 
734
- private disconnectHandler(reason: string, error?: IAnyDriverError) {
784
+ private disconnectHandler(reason: IConnectionStateChangeReason) {
735
785
  this.messageBuffer.length = 0;
736
- this.emit("disconnect", reason, error);
786
+ this.emit("disconnect", reason);
737
787
  }
738
788
 
739
789
  /**
@@ -893,7 +943,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
893
943
  // pre-0.58 error message: twoMessagesWithSameSeqNumAndDifferentPayload
894
944
  "Found two messages with the same sequenceNumber but different payloads. Likely to be a " +
895
945
  "service issue",
896
- DriverErrorType.fileOverwrittenInStorage,
946
+ DriverErrorTypes.fileOverwrittenInStorage,
897
947
  {
898
948
  clientId: this.connectionManager.clientId,
899
949
  sequenceNumber: message.sequenceNumber,
package/src/deltaQueue.ts CHANGED
@@ -4,7 +4,8 @@
4
4
  */
5
5
 
6
6
  import { IDeltaQueue, IDeltaQueueEvents } from "@fluidframework/container-definitions";
7
- import { assert, performance, TypedEventEmitter } from "@fluidframework/common-utils";
7
+ import { assert } from "@fluidframework/core-utils";
8
+ import { performance, TypedEventEmitter } from "@fluid-internal/client-utils";
8
9
  import Deque from "double-ended-queue";
9
10
 
10
11
  export interface IDeltaQueueWriter<T> {
package/src/disposal.ts CHANGED
@@ -3,11 +3,11 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IDisposable } from "@fluidframework/common-definitions";
6
+ import { IDisposable } from "@fluidframework/core-interfaces";
7
7
 
8
8
  /**
9
9
  * Returns a wrapper around the provided function, which will only invoke the inner function if the provided
10
- * {@link @fluidframework/common-definitions#IDisposable | disposable} object has not yet been disposed.
10
+ * {@link @fluidframework/core-interfaces#IDisposable | disposable} object has not yet been disposed.
11
11
  *
12
12
  * @throws Will throw an error if the item has already been disposed.
13
13
  */
package/src/error.ts ADDED
@@ -0,0 +1,44 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { ITelemetryProperties, IThrottlingWarning } from "@fluidframework/core-interfaces";
7
+ import { ContainerErrorTypes } from "@fluidframework/container-definitions";
8
+ import {
9
+ IFluidErrorBase,
10
+ ITelemetryLoggerExt,
11
+ LoggingError,
12
+ wrapErrorAndLog,
13
+ } from "@fluidframework/telemetry-utils";
14
+
15
+ /**
16
+ * Warning emitted when requests to storage are being throttled.
17
+ */
18
+ export class ThrottlingWarning extends LoggingError implements IThrottlingWarning, IFluidErrorBase {
19
+ /**
20
+ * {@inheritDoc @fluidframework/telemetry-utils#IFluidErrorBase.errorType}
21
+ */
22
+ public readonly errorType = ContainerErrorTypes.throttlingError;
23
+
24
+ private constructor(
25
+ message: string,
26
+ readonly retryAfterSeconds: number,
27
+ props?: ITelemetryProperties,
28
+ ) {
29
+ super(message, props);
30
+ }
31
+
32
+ /**
33
+ * Wrap the given error as a ThrottlingWarning
34
+ * Only preserves the error message, and applies the given retry after to the new warning object
35
+ */
36
+ public static wrap(
37
+ error: unknown,
38
+ retryAfterSeconds: number,
39
+ logger: ITelemetryLoggerExt,
40
+ ): IThrottlingWarning {
41
+ const newErrorFn = (errMsg: string) => new ThrottlingWarning(errMsg, retryAfterSeconds);
42
+ return wrapErrorAndLog(error, newErrorFn, logger);
43
+ }
44
+ }