@fluidframework/container-loader 2.0.0-internal.6.0.0 → 2.0.0-internal.6.1.1

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 (68) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/connectionManager.d.ts +3 -3
  3. package/dist/connectionManager.d.ts.map +1 -1
  4. package/dist/connectionManager.js +33 -24
  5. package/dist/connectionManager.js.map +1 -1
  6. package/dist/connectionStateHandler.d.ts +14 -14
  7. package/dist/connectionStateHandler.d.ts.map +1 -1
  8. package/dist/connectionStateHandler.js +17 -12
  9. package/dist/connectionStateHandler.js.map +1 -1
  10. package/dist/container.d.ts.map +1 -1
  11. package/dist/container.js +27 -39
  12. package/dist/container.js.map +1 -1
  13. package/dist/containerContext.d.ts +6 -1
  14. package/dist/containerContext.d.ts.map +1 -1
  15. package/dist/containerContext.js +8 -1
  16. package/dist/containerContext.js.map +1 -1
  17. package/dist/contracts.d.ts +11 -7
  18. package/dist/contracts.d.ts.map +1 -1
  19. package/dist/contracts.js.map +1 -1
  20. package/dist/deltaManager.d.ts +4 -4
  21. package/dist/deltaManager.d.ts.map +1 -1
  22. package/dist/deltaManager.js +5 -4
  23. package/dist/deltaManager.js.map +1 -1
  24. package/dist/packageVersion.d.ts +1 -1
  25. package/dist/packageVersion.js +1 -1
  26. package/dist/packageVersion.js.map +1 -1
  27. package/dist/protocol.d.ts +4 -2
  28. package/dist/protocol.d.ts.map +1 -1
  29. package/dist/protocol.js +23 -1
  30. package/dist/protocol.js.map +1 -1
  31. package/lib/connectionManager.d.ts +3 -3
  32. package/lib/connectionManager.d.ts.map +1 -1
  33. package/lib/connectionManager.js +33 -24
  34. package/lib/connectionManager.js.map +1 -1
  35. package/lib/connectionStateHandler.d.ts +14 -14
  36. package/lib/connectionStateHandler.d.ts.map +1 -1
  37. package/lib/connectionStateHandler.js +17 -12
  38. package/lib/connectionStateHandler.js.map +1 -1
  39. package/lib/container.d.ts.map +1 -1
  40. package/lib/container.js +28 -40
  41. package/lib/container.js.map +1 -1
  42. package/lib/containerContext.d.ts +6 -1
  43. package/lib/containerContext.d.ts.map +1 -1
  44. package/lib/containerContext.js +8 -1
  45. package/lib/containerContext.js.map +1 -1
  46. package/lib/contracts.d.ts +11 -7
  47. package/lib/contracts.d.ts.map +1 -1
  48. package/lib/contracts.js.map +1 -1
  49. package/lib/deltaManager.d.ts +4 -4
  50. package/lib/deltaManager.d.ts.map +1 -1
  51. package/lib/deltaManager.js +5 -4
  52. package/lib/deltaManager.js.map +1 -1
  53. package/lib/packageVersion.d.ts +1 -1
  54. package/lib/packageVersion.js +1 -1
  55. package/lib/packageVersion.js.map +1 -1
  56. package/lib/protocol.d.ts +4 -2
  57. package/lib/protocol.d.ts.map +1 -1
  58. package/lib/protocol.js +23 -1
  59. package/lib/protocol.js.map +1 -1
  60. package/package.json +14 -14
  61. package/src/connectionManager.ts +46 -31
  62. package/src/connectionStateHandler.ts +28 -36
  63. package/src/container.ts +47 -51
  64. package/src/containerContext.ts +8 -0
  65. package/src/contracts.ts +12 -6
  66. package/src/deltaManager.ts +19 -13
  67. package/src/packageVersion.ts +1 -1
  68. package/src/protocol.ts +33 -1
@@ -45,6 +45,13 @@ export class ContainerContext implements IContainerContext {
45
45
  return this._getClientId();
46
46
  }
47
47
 
48
+ /**
49
+ * DISCLAIMER: this id is only for telemetry purposes. Not suitable for any other usages.
50
+ */
51
+ public get id(): string {
52
+ return this._getContainerDiagnosticId() ?? "";
53
+ }
54
+
48
55
  /**
49
56
  * When true, ops are free to flow
50
57
  * When false, ops should be kept as pending or rejected
@@ -83,6 +90,7 @@ export class ContainerContext implements IContainerContext {
83
90
  public readonly closeFn: (error?: ICriticalContainerError) => void,
84
91
  public readonly updateDirtyContainerState: (dirty: boolean) => void,
85
92
  public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>,
93
+ private readonly _getContainerDiagnosticId: () => string | undefined,
86
94
  private readonly _getClientId: () => string | undefined,
87
95
  private readonly _getAttachState: () => AttachState,
88
96
  private readonly _getConnected: () => boolean,
package/src/contracts.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  IConnectionDetails,
9
9
  ICriticalContainerError,
10
10
  IDeltaQueue,
11
+ IErrorBase,
11
12
  IFluidCodeDetails,
12
13
  isFluidPackage,
13
14
  ReadOnlyInfo,
@@ -21,7 +22,7 @@ import {
21
22
  ISignalClient,
22
23
  ISignalMessage,
23
24
  } from "@fluidframework/protocol-definitions";
24
- import { IAnyDriverError, IContainerPackageInfo } from "@fluidframework/driver-definitions";
25
+ import { IContainerPackageInfo } from "@fluidframework/driver-definitions";
25
26
 
26
27
  export enum ReconnectMode {
27
28
  Never = "Never",
@@ -29,6 +30,11 @@ export enum ReconnectMode {
29
30
  Enabled = "Enabled",
30
31
  }
31
32
 
33
+ export interface IConnectionStateChangeReason<T extends IErrorBase = IErrorBase> {
34
+ text: string;
35
+ error?: T;
36
+ }
37
+
32
38
  /**
33
39
  * Internal version of IConnectionDetails with props are only exposed internally
34
40
  */
@@ -36,7 +42,7 @@ export interface IConnectionDetailsInternal extends IConnectionDetails {
36
42
  mode: ConnectionMode;
37
43
  version: string;
38
44
  initialClients: ISignalClient[];
39
- reason: string;
45
+ reason: IConnectionStateChangeReason;
40
46
  }
41
47
 
42
48
  /**
@@ -106,7 +112,7 @@ export interface IConnectionManager {
106
112
  /**
107
113
  * Initiates connection to relay service (noop if already connected).
108
114
  */
109
- connect(reason: string, connectionMode?: ConnectionMode): void;
115
+ connect(reason: IConnectionStateChangeReason, connectionMode?: ConnectionMode): void;
110
116
 
111
117
  /**
112
118
  * Disposed connection manager
@@ -150,7 +156,7 @@ export interface IConnectionManagerFactoryArgs {
150
156
  /**
151
157
  * Called whenever connection to relay service is lost.
152
158
  */
153
- readonly disconnectHandler: (reason: string, error?: IAnyDriverError) => void;
159
+ readonly disconnectHandler: (reason: IConnectionStateChangeReason) => void;
154
160
 
155
161
  /**
156
162
  * Called whenever new connection to rely service is established
@@ -180,12 +186,12 @@ export interface IConnectionManagerFactoryArgs {
180
186
  /**
181
187
  * Called whenever we try to start establishing a new connection.
182
188
  */
183
- readonly establishConnectionHandler: (reason: string) => void;
189
+ readonly establishConnectionHandler: (reason: IConnectionStateChangeReason) => void;
184
190
 
185
191
  /**
186
192
  * Called whenever we cancel the connection in progress.
187
193
  */
188
- readonly cancelConnectionHandler: (reason: string) => void;
194
+ readonly cancelConnectionHandler: (reason: IConnectionStateChangeReason) => void;
189
195
  }
190
196
 
191
197
  /**
@@ -25,7 +25,6 @@ import {
25
25
  IDocumentDeltaStorageService,
26
26
  IDocumentService,
27
27
  DriverErrorType,
28
- IAnyDriverError,
29
28
  } from "@fluidframework/driver-definitions";
30
29
  import {
31
30
  IDocumentMessage,
@@ -46,6 +45,7 @@ import {
46
45
  IConnectionDetailsInternal,
47
46
  IConnectionManager,
48
47
  IConnectionManagerFactoryArgs,
48
+ IConnectionStateChangeReason,
49
49
  } from "./contracts";
50
50
  import { DeltaQueue } from "./deltaQueue";
51
51
  import { OnlyValidTermValue } from "./protocol";
@@ -53,7 +53,7 @@ import { OnlyValidTermValue } from "./protocol";
53
53
  export interface IConnectionArgs {
54
54
  mode?: ConnectionMode;
55
55
  fetchOpsFromStorage?: boolean;
56
- reason: string;
56
+ reason: IConnectionStateChangeReason;
57
57
  }
58
58
 
59
59
  /**
@@ -64,8 +64,11 @@ export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
64
64
  (event: "throttled", listener: (error: IThrottlingWarning) => void);
65
65
  (event: "closed" | "disposed", listener: (error?: ICriticalContainerError) => void);
66
66
  (event: "connect", listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void);
67
- (event: "establishingConnection", listener: (reason: string) => void);
68
- (event: "cancelEstablishingConnection", listener: (reason: string) => void);
67
+ (event: "establishingConnection", listener: (reason: IConnectionStateChangeReason) => void);
68
+ (
69
+ event: "cancelEstablishingConnection",
70
+ listener: (reason: IConnectionStateChangeReason) => void,
71
+ );
69
72
  }
70
73
 
71
74
  /**
@@ -347,6 +350,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
347
350
  return {
348
351
  sequenceNumber: this.lastSequenceNumber,
349
352
  opsSize: this.opsSize > 0 ? this.opsSize : undefined,
353
+ deltaManagerState: this._disposed ? "disposed" : this._closed ? "closed" : "open",
350
354
  ...this.connectionManager.connectionProps,
351
355
  };
352
356
  }
@@ -400,15 +404,17 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
400
404
  reconnectionDelayHandler: (delayMs: number, error: unknown) =>
401
405
  this.emitDelayInfo(this.deltaStreamDelayId, delayMs, error),
402
406
  closeHandler: (error: any) => this.close(error),
403
- disconnectHandler: (reason: string, error?: IAnyDriverError) =>
404
- this.disconnectHandler(reason, error),
407
+ disconnectHandler: (reason: IConnectionStateChangeReason) =>
408
+ this.disconnectHandler(reason),
405
409
  connectHandler: (connection: IConnectionDetailsInternal) =>
406
410
  this.connectHandler(connection),
407
411
  pongHandler: (latency: number) => this.emit("pong", latency),
408
412
  readonlyChangeHandler: (readonly?: boolean) =>
409
413
  safeRaiseEvent(this, this.logger, "readonly", readonly),
410
- establishConnectionHandler: (reason: string) => this.establishingConnection(reason),
411
- cancelConnectionHandler: (reason: string) => this.cancelEstablishingConnection(reason),
414
+ establishConnectionHandler: (reason: IConnectionStateChangeReason) =>
415
+ this.establishingConnection(reason),
416
+ cancelConnectionHandler: (reason: IConnectionStateChangeReason) =>
417
+ this.cancelEstablishingConnection(reason),
412
418
  };
413
419
 
414
420
  this.connectionManager = createConnectionManager(props);
@@ -448,11 +454,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
448
454
  // - inbound & inboundSignal are resumed in attachOpHandler() when we have handler setup
449
455
  }
450
456
 
451
- private cancelEstablishingConnection(reason: string) {
457
+ private cancelEstablishingConnection(reason: IConnectionStateChangeReason) {
452
458
  this.emit("cancelEstablishingConnection", reason);
453
459
  }
454
460
 
455
- private establishingConnection(reason: string) {
461
+ private establishingConnection(reason: IConnectionStateChangeReason) {
456
462
  this.emit("establishingConnection", reason);
457
463
  }
458
464
 
@@ -586,7 +592,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
586
592
  // on the wire, we might be always behind.
587
593
  // See comment at the end of "connect" handler
588
594
  if (fetchOpsFromStorage) {
589
- this.fetchMissingDeltas(args.reason);
595
+ this.fetchMissingDeltas(args.reason.text);
590
596
  }
591
597
 
592
598
  this.connectionManager.connect(args.reason, args.mode);
@@ -772,9 +778,9 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
772
778
  }
773
779
  }
774
780
 
775
- private disconnectHandler(reason: string, error?: IAnyDriverError) {
781
+ private disconnectHandler(reason: IConnectionStateChangeReason) {
776
782
  this.messageBuffer.length = 0;
777
- this.emit("disconnect", reason, error);
783
+ this.emit("disconnect", reason);
778
784
  }
779
785
 
780
786
  /**
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-internal.6.0.0";
9
+ export const pkgVersion = "2.0.0-internal.6.1.1";
package/src/protocol.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { IAudienceOwner } from "@fluidframework/container-definitions";
7
+ import { canBeCoalescedByService } from "@fluidframework/driver-utils";
7
8
  import {
8
9
  IProtocolHandler as IBaseProtocolHandler,
9
10
  IQuorumSnapshot,
@@ -11,8 +12,12 @@ import {
11
12
  } from "@fluidframework/protocol-base";
12
13
  import {
13
14
  IDocumentAttributes,
15
+ IProcessMessageResult,
16
+ ISequencedClient,
17
+ ISequencedDocumentMessage,
14
18
  ISignalClient,
15
19
  ISignalMessage,
20
+ MessageType,
16
21
  } from "@fluidframework/protocol-definitions";
17
22
 
18
23
  // "term" was an experimental feature that is being removed. The only safe value to use is 1.
@@ -44,7 +49,8 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
44
49
  attributes: IDocumentAttributes,
45
50
  quorumSnapshot: IQuorumSnapshot,
46
51
  sendProposal: (key: string, value: any) => number,
47
- readonly audience: IAudienceOwner,
52
+ public readonly audience: IAudienceOwner,
53
+ private readonly shouldClientHaveLeft: (clientId: string) => boolean,
48
54
  ) {
49
55
  super(
50
56
  attributes.minimumSequenceNumber,
@@ -65,6 +71,32 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
65
71
  }
66
72
  }
67
73
 
74
+ public processMessage(
75
+ message: ISequencedDocumentMessage,
76
+ local: boolean,
77
+ ): IProcessMessageResult {
78
+ const client: ISequencedClient | undefined = this.quorum.getMember(message.clientId);
79
+
80
+ // Check and report if we're getting messages from a clientId that we previously
81
+ // flagged as shouldHaveLeft, or from a client that's not in the quorum but should be
82
+ if (message.clientId != null) {
83
+ if (client === undefined && message.type !== MessageType.ClientJoin) {
84
+ // pre-0.58 error message: messageClientIdMissingFromQuorum
85
+ throw new Error("Remote message's clientId is missing from the quorum");
86
+ }
87
+
88
+ // Here checking canBeCoalescedByService is used as an approximation of "is benign to process despite being unexpected".
89
+ // It's still not good to see these messages from unexpected clientIds, but since they don't harm the integrity of the
90
+ // document we don't need to blow up aggressively.
91
+ if (this.shouldClientHaveLeft(message.clientId) && !canBeCoalescedByService(message)) {
92
+ // pre-0.58 error message: messageClientIdShouldHaveLeft
93
+ throw new Error("Remote message's clientId already should have left");
94
+ }
95
+ }
96
+
97
+ return super.processMessage(message, local);
98
+ }
99
+
68
100
  public processSignal(message: ISignalMessage) {
69
101
  const innerContent = message.content as { content: any; type: string };
70
102
  switch (innerContent.type) {