@fluid-experimental/oldest-client-observer 2.0.0-internal.8.0.0 → 2.0.0-rc.1.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 (41) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +0 -6
  3. package/api-extractor-esm.json +4 -0
  4. package/api-extractor-lint.json +1 -10
  5. package/api-extractor.json +1 -9
  6. package/api-report/oldest-client-observer.api.md +5 -5
  7. package/dist/{index.cjs → index.js} +2 -2
  8. package/dist/index.js.map +1 -0
  9. package/dist/interfaces.d.ts +4 -4
  10. package/dist/{interfaces.cjs → interfaces.js} +1 -1
  11. package/dist/interfaces.js.map +1 -0
  12. package/dist/oldest-client-observer-alpha.d.ts +99 -5
  13. package/dist/oldest-client-observer-beta.d.ts +0 -8
  14. package/dist/oldest-client-observer-public.d.ts +0 -8
  15. package/dist/oldest-client-observer-untrimmed.d.ts +5 -5
  16. package/dist/oldestClientObserver.d.ts +1 -1
  17. package/dist/{oldestClientObserver.cjs → oldestClientObserver.js} +2 -2
  18. package/dist/oldestClientObserver.js.map +1 -0
  19. package/lib/{index.d.ts → index.d.mts} +1 -1
  20. package/lib/index.d.mts.map +1 -0
  21. package/lib/{interfaces.d.ts → interfaces.d.mts} +5 -5
  22. package/lib/interfaces.d.mts.map +1 -0
  23. package/lib/interfaces.mjs.map +1 -1
  24. package/lib/{oldest-client-observer-untrimmed.d.ts → oldest-client-observer-alpha.d.mts} +5 -5
  25. package/lib/{oldest-client-observer-beta.d.ts → oldest-client-observer-public.d.mts} +0 -8
  26. package/lib/oldest-client-observer-untrimmed.d.mts +111 -0
  27. package/lib/{oldestClientObserver.d.ts → oldestClientObserver.d.mts} +2 -2
  28. package/lib/oldestClientObserver.d.mts.map +1 -0
  29. package/lib/oldestClientObserver.mjs +1 -1
  30. package/lib/oldestClientObserver.mjs.map +1 -1
  31. package/package.json +72 -18
  32. package/src/interfaces.ts +4 -4
  33. package/src/oldestClientObserver.ts +1 -1
  34. package/dist/index.cjs.map +0 -1
  35. package/dist/interfaces.cjs.map +0 -1
  36. package/dist/oldestClientObserver.cjs.map +0 -1
  37. package/lib/index.d.ts.map +0 -1
  38. package/lib/interfaces.d.ts.map +0 -1
  39. package/lib/oldest-client-observer-public.d.ts +0 -25
  40. package/lib/oldestClientObserver.d.ts.map +0 -1
  41. /package/lib/{oldest-client-observer-alpha.d.ts → oldest-client-observer-beta.d.mts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # @fluid-experimental/oldest-client-observer
2
2
 
3
+ ## 2.0.0-rc.1.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Updated server dependencies ([#19122](https://github.com/microsoft/FluidFramework/issues/19122)) [25366b4229](https://github.com/microsoft/FluidFramework/commits/25366b422918cb43685c5f328b50450749592902)
8
+
9
+ The following Fluid server dependencies have been updated to the latest version, 3.0.0. [See the full changelog.](https://github.com/microsoft/FluidFramework/releases/tag/server_v3.0.0)
10
+
11
+ - @fluidframework/gitresources
12
+ - @fluidframework/server-kafka-orderer
13
+ - @fluidframework/server-lambdas
14
+ - @fluidframework/server-lambdas-driver
15
+ - @fluidframework/server-local-server
16
+ - @fluidframework/server-memory-orderer
17
+ - @fluidframework/protocol-base
18
+ - @fluidframework/server-routerlicious
19
+ - @fluidframework/server-routerlicious-base
20
+ - @fluidframework/server-services
21
+ - @fluidframework/server-services-client
22
+ - @fluidframework/server-services-core
23
+ - @fluidframework/server-services-ordering-kafkanode
24
+ - @fluidframework/server-services-ordering-rdkafka
25
+ - @fluidframework/server-services-ordering-zookeeper
26
+ - @fluidframework/server-services-shared
27
+ - @fluidframework/server-services-telemetry
28
+ - @fluidframework/server-services-utils
29
+ - @fluidframework/server-test-utils
30
+ - tinylicious
31
+
32
+ - Updated @fluidframework/protocol-definitions ([#19122](https://github.com/microsoft/FluidFramework/issues/19122)) [25366b4229](https://github.com/microsoft/FluidFramework/commits/25366b422918cb43685c5f328b50450749592902)
33
+
34
+ The @fluidframework/protocol-definitions dependency has been upgraded to v3.1.0. [See the full
35
+ changelog.](https://github.com/microsoft/FluidFramework/blob/main/common/lib/protocol-definitions/CHANGELOG.md#310)
36
+
3
37
  ## 2.0.0-internal.8.0.0
4
38
 
5
39
  Dependency updates only.
package/README.md CHANGED
@@ -11,12 +11,6 @@ When taking a dependency on a Fluid Framework library, we recommend using a `^`
11
11
  While Fluid Framework libraries may use different ranges with interdependencies between other Fluid Framework libraries,
12
12
  library consumers should always prefer `^`.
13
13
 
14
- Note that when depending on a library version of the form `2.0.0-internal.x.y.z`, called the Fluid internal version scheme,
15
- you must use a `>= <` dependency range (such as `>=2.0.0-internal.x.y.z <2.0.0-internal.w.0.0` where `w` is `x+1`).
16
- Standard `^` and `~` ranges will not work as expected.
17
- See the [@fluid-tools/version-tools](https://github.com/microsoft/FluidFramework/blob/main/build-tools/packages/version-tools/README.md)
18
- package for more information including tools to convert between version schemes.
19
-
20
14
  <!-- prettier-ignore-end -->
21
15
 
22
16
  <!-- AUTO-GENERATED-CONTENT:END -->
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
+ "extends": "../../../common/build/build-common/api-extractor-base-esm.json"
4
+ }
@@ -1,13 +1,4 @@
1
1
  {
2
2
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
- "extends": "../../../common/build/build-common/api-extractor-lint.json",
4
- "messages": {
5
- "extractorMessageReporting": {
6
- // TODO: remove once base config has this enabled as an error
7
- "ae-incompatible-release-tags": {
8
- "logLevel": "error",
9
- "addToApiReportFile": false
10
- }
11
- }
12
- }
3
+ "extends": "../../../common/build/build-common/api-extractor-lint.json"
13
4
  }
@@ -1,12 +1,4 @@
1
1
  {
2
2
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
- "extends": "../../../common/build/build-common/api-extractor-base.json",
4
- "messages": {
5
- "extractorMessageReporting": {
6
- // TODO: Add missing documentation and remove this rule override
7
- "ae-undocumented": {
8
- "logLevel": "none"
9
- }
10
- }
11
- }
3
+ "extends": "../../../common/build/build-common/api-extractor-base.json"
12
4
  }
@@ -10,7 +10,7 @@ import { IEventProvider } from '@fluidframework/core-interfaces';
10
10
  import { IQuorumClients } from '@fluidframework/protocol-definitions';
11
11
  import { TypedEventEmitter } from '@fluid-internal/client-utils';
12
12
 
13
- // @internal
13
+ // @alpha
14
14
  export interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
15
15
  // (undocumented)
16
16
  attachState: AttachState;
@@ -22,7 +22,7 @@ export interface IOldestClientObservable extends IEventProvider<IOldestClientObs
22
22
  getQuorum(): IQuorumClients;
23
23
  }
24
24
 
25
- // @internal
25
+ // @alpha
26
26
  export interface IOldestClientObservableEvents extends IEvent {
27
27
  // (undocumented)
28
28
  (event: "connected", listener: () => void): any;
@@ -30,19 +30,19 @@ export interface IOldestClientObservableEvents extends IEvent {
30
30
  (event: "disconnected", listener: () => void): any;
31
31
  }
32
32
 
33
- // @internal (undocumented)
33
+ // @alpha (undocumented)
34
34
  export interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
35
35
  // (undocumented)
36
36
  isOldest(): boolean;
37
37
  }
38
38
 
39
- // @internal
39
+ // @alpha
40
40
  export interface IOldestClientObserverEvents extends IEvent {
41
41
  // (undocumented)
42
42
  (event: "becameOldest" | "lostOldest", listener: () => void): any;
43
43
  }
44
44
 
45
- // @internal
45
+ // @alpha
46
46
  export class OldestClientObserver extends TypedEventEmitter<IOldestClientObserverEvents> implements IOldestClientObserver {
47
47
  constructor(observable: IOldestClientObservable);
48
48
  // (undocumented)
@@ -5,6 +5,6 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.OldestClientObserver = void 0;
8
- var oldestClientObserver_1 = require("./oldestClientObserver.cjs");
8
+ var oldestClientObserver_1 = require("./oldestClientObserver");
9
9
  Object.defineProperty(exports, "OldestClientObserver", { enumerable: true, get: function () { return oldestClientObserver_1.OldestClientObserver; } });
10
- //# sourceMappingURL=index.cjs.map
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tIOldestClientObservable,\n\tIOldestClientObservableEvents,\n\tIOldestClientObserver,\n\tIOldestClientObserverEvents,\n} from \"./interfaces\";\nexport { OldestClientObserver } from \"./oldestClientObserver\";\n"]}
@@ -7,7 +7,7 @@ import { AttachState } from "@fluidframework/container-definitions";
7
7
  import { IQuorumClients } from "@fluidframework/protocol-definitions";
8
8
  /**
9
9
  * Events emitted by {@link IOldestClientObservable}.
10
- * @internal
10
+ * @alpha
11
11
  */
12
12
  export interface IOldestClientObservableEvents extends IEvent {
13
13
  (event: "connected", listener: () => void): any;
@@ -18,7 +18,7 @@ export interface IOldestClientObservableEvents extends IEvent {
18
18
  * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,
19
19
  * since neither is really the source of truth (they are just the only currently-available plumbing options).
20
20
  * It's information about the connection, so the real source of truth is lower (at the connection layer).
21
- * @internal
21
+ * @alpha
22
22
  */
23
23
  export interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
24
24
  getQuorum(): IQuorumClients;
@@ -28,13 +28,13 @@ export interface IOldestClientObservable extends IEventProvider<IOldestClientObs
28
28
  }
29
29
  /**
30
30
  * Events emitted by {@link IOldestClientObservable}.
31
- * @internal
31
+ * @alpha
32
32
  */
33
33
  export interface IOldestClientObserverEvents extends IEvent {
34
34
  (event: "becameOldest" | "lostOldest", listener: () => void): any;
35
35
  }
36
36
  /**
37
- * @internal
37
+ * @alpha
38
38
  */
39
39
  export interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
40
40
  isOldest(): boolean;
@@ -4,4 +4,4 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- //# sourceMappingURL=interfaces.cjs.map
7
+ //# sourceMappingURL=interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IEvent, IEventProvider } from \"@fluidframework/core-interfaces\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @alpha\n */\nexport interface IOldestClientObservableEvents extends IEvent {\n\t(event: \"connected\", listener: () => void);\n\t(event: \"disconnected\", listener: () => void);\n}\n\n/**\n * This is to make OldestClientObserver work with either a ContainerRuntime or an IFluidDataStoreRuntime\n * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,\n * since neither is really the source of truth (they are just the only currently-available plumbing options).\n * It's information about the connection, so the real source of truth is lower (at the connection layer).\n * @alpha\n */\nexport interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {\n\tgetQuorum(): IQuorumClients;\n\t// Generic usage of attachState is a little unusual here. We will treat ourselves as \"the oldest client that\n\t// has information about this [container | data store]\", which in the case of detached data store may disagree\n\t// with whether we're the oldest client on the connected container. So in the data store case, it's only\n\t// safe use this as an indicator about rights to tasks performed against this specific data store, and not\n\t// more broadly.\n\tattachState: AttachState;\n\tconnected: boolean;\n\tclientId: string | undefined;\n}\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @alpha\n */\nexport interface IOldestClientObserverEvents extends IEvent {\n\t(event: \"becameOldest\" | \"lostOldest\", listener: () => void);\n}\n\n/**\n * @alpha\n */\nexport interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {\n\tisOldest(): boolean;\n}\n"]}
@@ -4,14 +4,108 @@ import { IEventProvider } from '@fluidframework/core-interfaces';
4
4
  import { IQuorumClients } from '@fluidframework/protocol-definitions';
5
5
  import { TypedEventEmitter } from '@fluid-internal/client-utils';
6
6
 
7
- /* Excluded from this release type: IOldestClientObservable */
7
+ /**
8
+ * This is to make OldestClientObserver work with either a ContainerRuntime or an IFluidDataStoreRuntime
9
+ * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,
10
+ * since neither is really the source of truth (they are just the only currently-available plumbing options).
11
+ * It's information about the connection, so the real source of truth is lower (at the connection layer).
12
+ * @alpha
13
+ */
14
+ export declare interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
15
+ getQuorum(): IQuorumClients;
16
+ attachState: AttachState;
17
+ connected: boolean;
18
+ clientId: string | undefined;
19
+ }
8
20
 
9
- /* Excluded from this release type: IOldestClientObservableEvents */
21
+ /**
22
+ * Events emitted by {@link IOldestClientObservable}.
23
+ * @alpha
24
+ */
25
+ export declare interface IOldestClientObservableEvents extends IEvent {
26
+ (event: "connected", listener: () => void): any;
27
+ (event: "disconnected", listener: () => void): any;
28
+ }
10
29
 
11
- /* Excluded from this release type: IOldestClientObserver */
30
+ /**
31
+ * @alpha
32
+ */
33
+ export declare interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
34
+ isOldest(): boolean;
35
+ }
12
36
 
13
- /* Excluded from this release type: IOldestClientObserverEvents */
37
+ /**
38
+ * Events emitted by {@link IOldestClientObservable}.
39
+ * @alpha
40
+ */
41
+ export declare interface IOldestClientObserverEvents extends IEvent {
42
+ (event: "becameOldest" | "lostOldest", listener: () => void): any;
43
+ }
14
44
 
15
- /* Excluded from this release type: OldestClientObserver */
45
+ /**
46
+ * The `OldestClientObserver` is a utility inspect if the local client is the oldest amongst connected clients (in
47
+ * terms of when they connected) and watch for changes.
48
+ *
49
+ * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.
50
+ *
51
+ * @remarks
52
+ * ### Creation
53
+ *
54
+ * The `OldestClientObserver` constructor takes an `IOldestClientObservable`. This is most easily satisfied with
55
+ * either an `IContainerRuntime` or an `IFluidDataStoreRuntime`:
56
+ *
57
+ * ```typescript
58
+ * // E.g. from within a BaseContainerRuntimeFactory:
59
+ * protected async containerHasInitialized(runtime: IContainerRuntime) {
60
+ * const oldestClientObserver = new OldestClientObserver(runtime);
61
+ * // ...
62
+ * }
63
+ * ```
64
+ *
65
+ * ```typescript
66
+ * // From within a DataObject
67
+ * protected async hasInitialized() {
68
+ * const oldestClientObserver = new OldestClientObserver(this.runtime);
69
+ * // ...
70
+ * }
71
+ * ```
72
+ *
73
+ * ### Usage
74
+ *
75
+ * To check if the local client is the oldest, use the `isOldest()` method.
76
+ *
77
+ * ```typescript
78
+ * if (oldestClientObserver.isOldest()) {
79
+ * console.log("I'm the oldest");
80
+ * } else {
81
+ * console.log("Someone else is older");
82
+ * }
83
+ * ```
84
+ *
85
+ * ### Eventing
86
+ *
87
+ * `OldestClientObserver` is an `EventEmitter`, and will emit events when the local client becomes the oldest and when
88
+ * it is no longer the oldest.
89
+ *
90
+ * ```typescript
91
+ * oldestClientObserver.on("becameOldest", () => {
92
+ * console.log("I'm the oldest now");
93
+ * });
94
+ *
95
+ * oldestClientObserver.on("lostOldest", () => {
96
+ * console.log("I'm not the oldest anymore");
97
+ * });
98
+ * ```
99
+ * @alpha
100
+ */
101
+ export declare class OldestClientObserver extends TypedEventEmitter<IOldestClientObserverEvents> implements IOldestClientObserver {
102
+ private readonly observable;
103
+ private readonly quorum;
104
+ private currentIsOldest;
105
+ constructor(observable: IOldestClientObservable);
106
+ isOldest(): boolean;
107
+ private readonly updateOldest;
108
+ private computeIsOldest;
109
+ }
16
110
 
17
111
  export { }
@@ -4,12 +4,6 @@ import { IEventProvider } from '@fluidframework/core-interfaces';
4
4
  import { IQuorumClients } from '@fluidframework/protocol-definitions';
5
5
  import { TypedEventEmitter } from '@fluid-internal/client-utils';
6
6
 
7
- /* Excluded from this release type: AttachState */
8
-
9
- /* Excluded from this release type: IEvent */
10
-
11
- /* Excluded from this release type: IEventProvider */
12
-
13
7
  /* Excluded from this release type: IOldestClientObservable */
14
8
 
15
9
  /* Excluded from this release type: IOldestClientObservableEvents */
@@ -20,6 +14,4 @@ import { TypedEventEmitter } from '@fluid-internal/client-utils';
20
14
 
21
15
  /* Excluded from this release type: OldestClientObserver */
22
16
 
23
- /* Excluded from this release type: TypedEventEmitter */
24
-
25
17
  export { }
@@ -4,12 +4,6 @@ import { IEventProvider } from '@fluidframework/core-interfaces';
4
4
  import { IQuorumClients } from '@fluidframework/protocol-definitions';
5
5
  import { TypedEventEmitter } from '@fluid-internal/client-utils';
6
6
 
7
- /* Excluded from this release type: AttachState */
8
-
9
- /* Excluded from this release type: IEvent */
10
-
11
- /* Excluded from this release type: IEventProvider */
12
-
13
7
  /* Excluded from this release type: IOldestClientObservable */
14
8
 
15
9
  /* Excluded from this release type: IOldestClientObservableEvents */
@@ -20,6 +14,4 @@ import { TypedEventEmitter } from '@fluid-internal/client-utils';
20
14
 
21
15
  /* Excluded from this release type: OldestClientObserver */
22
16
 
23
- /* Excluded from this release type: TypedEventEmitter */
24
-
25
17
  export { }
@@ -9,7 +9,7 @@ import { TypedEventEmitter } from '@fluid-internal/client-utils';
9
9
  * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,
10
10
  * since neither is really the source of truth (they are just the only currently-available plumbing options).
11
11
  * It's information about the connection, so the real source of truth is lower (at the connection layer).
12
- * @internal
12
+ * @alpha
13
13
  */
14
14
  export declare interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
15
15
  getQuorum(): IQuorumClients;
@@ -20,7 +20,7 @@ export declare interface IOldestClientObservable extends IEventProvider<IOldestC
20
20
 
21
21
  /**
22
22
  * Events emitted by {@link IOldestClientObservable}.
23
- * @internal
23
+ * @alpha
24
24
  */
25
25
  export declare interface IOldestClientObservableEvents extends IEvent {
26
26
  (event: "connected", listener: () => void): any;
@@ -28,7 +28,7 @@ export declare interface IOldestClientObservableEvents extends IEvent {
28
28
  }
29
29
 
30
30
  /**
31
- * @internal
31
+ * @alpha
32
32
  */
33
33
  export declare interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
34
34
  isOldest(): boolean;
@@ -36,7 +36,7 @@ export declare interface IOldestClientObserver extends IEventProvider<IOldestCli
36
36
 
37
37
  /**
38
38
  * Events emitted by {@link IOldestClientObservable}.
39
- * @internal
39
+ * @alpha
40
40
  */
41
41
  export declare interface IOldestClientObserverEvents extends IEvent {
42
42
  (event: "becameOldest" | "lostOldest", listener: () => void): any;
@@ -96,7 +96,7 @@ export declare interface IOldestClientObserverEvents extends IEvent {
96
96
  * console.log("I'm not the oldest anymore");
97
97
  * });
98
98
  * ```
99
- * @internal
99
+ * @alpha
100
100
  */
101
101
  export declare class OldestClientObserver extends TypedEventEmitter<IOldestClientObserverEvents> implements IOldestClientObserver {
102
102
  private readonly observable;
@@ -58,7 +58,7 @@ import { IOldestClientObservable, IOldestClientObserverEvents, IOldestClientObse
58
58
  * console.log("I'm not the oldest anymore");
59
59
  * });
60
60
  * ```
61
- * @internal
61
+ * @alpha
62
62
  */
63
63
  export declare class OldestClientObserver extends TypedEventEmitter<IOldestClientObserverEvents> implements IOldestClientObserver {
64
64
  private readonly observable;
@@ -62,7 +62,7 @@ const container_definitions_1 = require("@fluidframework/container-definitions")
62
62
  * console.log("I'm not the oldest anymore");
63
63
  * });
64
64
  * ```
65
- * @internal
65
+ * @alpha
66
66
  */
67
67
  class OldestClientObserver extends client_utils_1.TypedEventEmitter {
68
68
  constructor(observable) {
@@ -120,4 +120,4 @@ class OldestClientObserver extends client_utils_1.TypedEventEmitter {
120
120
  }
121
121
  }
122
122
  exports.OldestClientObserver = OldestClientObserver;
123
- //# sourceMappingURL=oldestClientObserver.cjs.map
123
+ //# sourceMappingURL=oldestClientObserver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oldestClientObserver.js","sourceRoot":"","sources":["../src/oldestClientObserver.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;AACjE,2DAAoD;AACpD,iFAAoE;AAQpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAa,oBACZ,SAAQ,gCAA8C;IAKtD,YAA6B,UAAmC;QAC/D,KAAK,EAAE,CAAC;QADoB,eAAU,GAAV,UAAU,CAAyB;QADxD,oBAAe,GAAY,KAAK,CAAC;QAexB,iBAAY,GAAG,GAAS,EAAE;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,eAAe,KAAK,MAAM,EAAE;gBACpC,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC;gBAC9B,IAAI,MAAM,EAAE;oBACX,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;iBAC1B;qBAAM;oBACN,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;iBACxB;aACD;QACF,CAAC,CAAC;QAtBD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9C,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAcO,eAAe;QACtB,uGAAuG;QACvG,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,mCAAW,CAAC,QAAQ,EAAE;YACzD,OAAO,IAAI,CAAC;SACZ;QAED,kEAAkE;QAClE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE;YAC/B,OAAO,KAAK,CAAC;SACb;QAED,yDAAyD;QACzD,IAAA,mBAAM,EACL,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS;QACtC,4DAA4D;QAC5D,KAAK,CAAC,4CAA4C,CAClD,CAAC;QAEF,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC5E,wEAAwE;QACxE,IAAI,mBAAmB,KAAK,SAAS,EAAE;YACtC,OAAO,KAAK,CAAC;SACb;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACzC,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE;YAC/C,IAAI,eAAe,CAAC,cAAc,GAAG,mBAAmB,CAAC,cAAc,EAAE;gBACxE,OAAO,KAAK,CAAC;aACb;SACD;QAED,oCAAoC;QACpC,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAlED,oDAkEC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\nimport {\n\tIOldestClientObservable,\n\tIOldestClientObserverEvents,\n\tIOldestClientObserver,\n} from \"./interfaces\";\n\n/**\n * The `OldestClientObserver` is a utility inspect if the local client is the oldest amongst connected clients (in\n * terms of when they connected) and watch for changes.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * The `OldestClientObserver` constructor takes an `IOldestClientObservable`. This is most easily satisfied with\n * either an `IContainerRuntime` or an `IFluidDataStoreRuntime`:\n *\n * ```typescript\n * // E.g. from within a BaseContainerRuntimeFactory:\n * protected async containerHasInitialized(runtime: IContainerRuntime) {\n * const oldestClientObserver = new OldestClientObserver(runtime);\n * // ...\n * }\n * ```\n *\n * ```typescript\n * // From within a DataObject\n * protected async hasInitialized() {\n * const oldestClientObserver = new OldestClientObserver(this.runtime);\n * // ...\n * }\n * ```\n *\n * ### Usage\n *\n * To check if the local client is the oldest, use the `isOldest()` method.\n *\n * ```typescript\n * if (oldestClientObserver.isOldest()) {\n * console.log(\"I'm the oldest\");\n * } else {\n * console.log(\"Someone else is older\");\n * }\n * ```\n *\n * ### Eventing\n *\n * `OldestClientObserver` is an `EventEmitter`, and will emit events when the local client becomes the oldest and when\n * it is no longer the oldest.\n *\n * ```typescript\n * oldestClientObserver.on(\"becameOldest\", () => {\n * console.log(\"I'm the oldest now\");\n * });\n *\n * oldestClientObserver.on(\"lostOldest\", () => {\n * console.log(\"I'm not the oldest anymore\");\n * });\n * ```\n * @alpha\n */\nexport class OldestClientObserver\n\textends TypedEventEmitter<IOldestClientObserverEvents>\n\timplements IOldestClientObserver\n{\n\tprivate readonly quorum: IQuorumClients;\n\tprivate currentIsOldest: boolean = false;\n\tconstructor(private readonly observable: IOldestClientObservable) {\n\t\tsuper();\n\t\tthis.quorum = this.observable.getQuorum();\n\t\tthis.currentIsOldest = this.computeIsOldest();\n\t\tthis.quorum.on(\"addMember\", this.updateOldest);\n\t\tthis.quorum.on(\"removeMember\", this.updateOldest);\n\t\tobservable.on(\"connected\", this.updateOldest);\n\t\tobservable.on(\"disconnected\", this.updateOldest);\n\t}\n\n\tpublic isOldest(): boolean {\n\t\treturn this.currentIsOldest;\n\t}\n\n\tprivate readonly updateOldest = (): void => {\n\t\tconst oldest = this.computeIsOldest();\n\t\tif (this.currentIsOldest !== oldest) {\n\t\t\tthis.currentIsOldest = oldest;\n\t\t\tif (oldest) {\n\t\t\t\tthis.emit(\"becameOldest\");\n\t\t\t} else {\n\t\t\t\tthis.emit(\"lostOldest\");\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate computeIsOldest(): boolean {\n\t\t// If the container is detached, we are the only ones that know about it and are the oldest by default.\n\t\tif (this.observable.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// If we're not connected we can't be the oldest connected client.\n\t\tif (!this.observable.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\t\tassert(\n\t\t\tthis.observable.clientId !== undefined,\n\t\t\t// eslint-disable-next-line unicorn/numeric-separators-style\n\t\t\t0x1da /* \"Client id should be set if connected\" */,\n\t\t);\n\n\t\tconst selfSequencedClient = this.quorum.getMember(this.observable.clientId);\n\t\t// When in readonly mode our clientId will not be present in the quorum.\n\t\tif (selfSequencedClient === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst members = this.quorum.getMembers();\n\t\tfor (const sequencedClient of members.values()) {\n\t\t\tif (sequencedClient.sequenceNumber < selfSequencedClient.sequenceNumber) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// No member of the quorum was older\n\t\treturn true;\n\t}\n}\n"]}
@@ -4,4 +4,4 @@
4
4
  */
5
5
  export { IOldestClientObservable, IOldestClientObservableEvents, IOldestClientObserver, IOldestClientObserverEvents, } from "./interfaces.mjs";
6
6
  export { OldestClientObserver } from "./oldestClientObserver.mjs";
7
- //# sourceMappingURL=index.d.ts.map
7
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EACN,uBAAuB,EACvB,6BAA6B,EAC7B,qBAAqB,EACrB,2BAA2B,GAC3B;OACM,EAAE,oBAAoB,EAAE"}
@@ -7,7 +7,7 @@ import { AttachState } from "@fluidframework/container-definitions";
7
7
  import { IQuorumClients } from "@fluidframework/protocol-definitions";
8
8
  /**
9
9
  * Events emitted by {@link IOldestClientObservable}.
10
- * @internal
10
+ * @alpha
11
11
  */
12
12
  export interface IOldestClientObservableEvents extends IEvent {
13
13
  (event: "connected", listener: () => void): any;
@@ -18,7 +18,7 @@ export interface IOldestClientObservableEvents extends IEvent {
18
18
  * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,
19
19
  * since neither is really the source of truth (they are just the only currently-available plumbing options).
20
20
  * It's information about the connection, so the real source of truth is lower (at the connection layer).
21
- * @internal
21
+ * @alpha
22
22
  */
23
23
  export interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
24
24
  getQuorum(): IQuorumClients;
@@ -28,15 +28,15 @@ export interface IOldestClientObservable extends IEventProvider<IOldestClientObs
28
28
  }
29
29
  /**
30
30
  * Events emitted by {@link IOldestClientObservable}.
31
- * @internal
31
+ * @alpha
32
32
  */
33
33
  export interface IOldestClientObserverEvents extends IEvent {
34
34
  (event: "becameOldest" | "lostOldest", listener: () => void): any;
35
35
  }
36
36
  /**
37
- * @internal
37
+ * @alpha
38
38
  */
39
39
  export interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
40
40
  isOldest(): boolean;
41
41
  }
42
- //# sourceMappingURL=interfaces.d.ts.map
42
+ //# sourceMappingURL=interfaces.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.d.mts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,iCAAiC;OACjE,EAAE,WAAW,EAAE,MAAM,uCAAuC;OAC5D,EAAE,cAAc,EAAE,MAAM,sCAAsC;AAErE;;;GAGG;AACH,MAAM,WAAW,6BAA8B,SAAQ,MAAM;IAC5D,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;IAC3C,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CAC9C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,uBAAwB,SAAQ,cAAc,CAAC,6BAA6B,CAAC;IAC7F,SAAS,IAAI,cAAc,CAAC;IAM5B,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA4B,SAAQ,MAAM;IAC1D,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CAC7D;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,cAAc,CAAC,2BAA2B,CAAC;IACzF,QAAQ,IAAI,OAAO,CAAC;CACpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.mjs","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IEvent, IEventProvider } from \"@fluidframework/core-interfaces\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @internal\n */\nexport interface IOldestClientObservableEvents extends IEvent {\n\t(event: \"connected\", listener: () => void);\n\t(event: \"disconnected\", listener: () => void);\n}\n\n/**\n * This is to make OldestClientObserver work with either a ContainerRuntime or an IFluidDataStoreRuntime\n * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,\n * since neither is really the source of truth (they are just the only currently-available plumbing options).\n * It's information about the connection, so the real source of truth is lower (at the connection layer).\n * @internal\n */\nexport interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {\n\tgetQuorum(): IQuorumClients;\n\t// Generic usage of attachState is a little unusual here. We will treat ourselves as \"the oldest client that\n\t// has information about this [container | data store]\", which in the case of detached data store may disagree\n\t// with whether we're the oldest client on the connected container. So in the data store case, it's only\n\t// safe use this as an indicator about rights to tasks performed against this specific data store, and not\n\t// more broadly.\n\tattachState: AttachState;\n\tconnected: boolean;\n\tclientId: string | undefined;\n}\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @internal\n */\nexport interface IOldestClientObserverEvents extends IEvent {\n\t(event: \"becameOldest\" | \"lostOldest\", listener: () => void);\n}\n\n/**\n * @internal\n */\nexport interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {\n\tisOldest(): boolean;\n}\n"]}
1
+ {"version":3,"file":"interfaces.mjs","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IEvent, IEventProvider } from \"@fluidframework/core-interfaces\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @alpha\n */\nexport interface IOldestClientObservableEvents extends IEvent {\n\t(event: \"connected\", listener: () => void);\n\t(event: \"disconnected\", listener: () => void);\n}\n\n/**\n * This is to make OldestClientObserver work with either a ContainerRuntime or an IFluidDataStoreRuntime\n * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,\n * since neither is really the source of truth (they are just the only currently-available plumbing options).\n * It's information about the connection, so the real source of truth is lower (at the connection layer).\n * @alpha\n */\nexport interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {\n\tgetQuorum(): IQuorumClients;\n\t// Generic usage of attachState is a little unusual here. We will treat ourselves as \"the oldest client that\n\t// has information about this [container | data store]\", which in the case of detached data store may disagree\n\t// with whether we're the oldest client on the connected container. So in the data store case, it's only\n\t// safe use this as an indicator about rights to tasks performed against this specific data store, and not\n\t// more broadly.\n\tattachState: AttachState;\n\tconnected: boolean;\n\tclientId: string | undefined;\n}\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @alpha\n */\nexport interface IOldestClientObserverEvents extends IEvent {\n\t(event: \"becameOldest\" | \"lostOldest\", listener: () => void);\n}\n\n/**\n * @alpha\n */\nexport interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {\n\tisOldest(): boolean;\n}\n"]}
@@ -9,7 +9,7 @@ import { TypedEventEmitter } from '@fluid-internal/client-utils';
9
9
  * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,
10
10
  * since neither is really the source of truth (they are just the only currently-available plumbing options).
11
11
  * It's information about the connection, so the real source of truth is lower (at the connection layer).
12
- * @internal
12
+ * @alpha
13
13
  */
14
14
  export declare interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
15
15
  getQuorum(): IQuorumClients;
@@ -20,7 +20,7 @@ export declare interface IOldestClientObservable extends IEventProvider<IOldestC
20
20
 
21
21
  /**
22
22
  * Events emitted by {@link IOldestClientObservable}.
23
- * @internal
23
+ * @alpha
24
24
  */
25
25
  export declare interface IOldestClientObservableEvents extends IEvent {
26
26
  (event: "connected", listener: () => void): any;
@@ -28,7 +28,7 @@ export declare interface IOldestClientObservableEvents extends IEvent {
28
28
  }
29
29
 
30
30
  /**
31
- * @internal
31
+ * @alpha
32
32
  */
33
33
  export declare interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
34
34
  isOldest(): boolean;
@@ -36,7 +36,7 @@ export declare interface IOldestClientObserver extends IEventProvider<IOldestCli
36
36
 
37
37
  /**
38
38
  * Events emitted by {@link IOldestClientObservable}.
39
- * @internal
39
+ * @alpha
40
40
  */
41
41
  export declare interface IOldestClientObserverEvents extends IEvent {
42
42
  (event: "becameOldest" | "lostOldest", listener: () => void): any;
@@ -96,7 +96,7 @@ export declare interface IOldestClientObserverEvents extends IEvent {
96
96
  * console.log("I'm not the oldest anymore");
97
97
  * });
98
98
  * ```
99
- * @internal
99
+ * @alpha
100
100
  */
101
101
  export declare class OldestClientObserver extends TypedEventEmitter<IOldestClientObserverEvents> implements IOldestClientObserver {
102
102
  private readonly observable;
@@ -4,12 +4,6 @@ import { IEventProvider } from '@fluidframework/core-interfaces';
4
4
  import { IQuorumClients } from '@fluidframework/protocol-definitions';
5
5
  import { TypedEventEmitter } from '@fluid-internal/client-utils';
6
6
 
7
- /* Excluded from this release type: AttachState */
8
-
9
- /* Excluded from this release type: IEvent */
10
-
11
- /* Excluded from this release type: IEventProvider */
12
-
13
7
  /* Excluded from this release type: IOldestClientObservable */
14
8
 
15
9
  /* Excluded from this release type: IOldestClientObservableEvents */
@@ -20,6 +14,4 @@ import { TypedEventEmitter } from '@fluid-internal/client-utils';
20
14
 
21
15
  /* Excluded from this release type: OldestClientObserver */
22
16
 
23
- /* Excluded from this release type: TypedEventEmitter */
24
-
25
17
  export { }
@@ -0,0 +1,111 @@
1
+ import { AttachState } from '@fluidframework/container-definitions';
2
+ import { IEvent } from '@fluidframework/core-interfaces';
3
+ import { IEventProvider } from '@fluidframework/core-interfaces';
4
+ import { IQuorumClients } from '@fluidframework/protocol-definitions';
5
+ import { TypedEventEmitter } from '@fluid-internal/client-utils';
6
+
7
+ /**
8
+ * This is to make OldestClientObserver work with either a ContainerRuntime or an IFluidDataStoreRuntime
9
+ * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,
10
+ * since neither is really the source of truth (they are just the only currently-available plumbing options).
11
+ * It's information about the connection, so the real source of truth is lower (at the connection layer).
12
+ * @alpha
13
+ */
14
+ export declare interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
15
+ getQuorum(): IQuorumClients;
16
+ attachState: AttachState;
17
+ connected: boolean;
18
+ clientId: string | undefined;
19
+ }
20
+
21
+ /**
22
+ * Events emitted by {@link IOldestClientObservable}.
23
+ * @alpha
24
+ */
25
+ export declare interface IOldestClientObservableEvents extends IEvent {
26
+ (event: "connected", listener: () => void): any;
27
+ (event: "disconnected", listener: () => void): any;
28
+ }
29
+
30
+ /**
31
+ * @alpha
32
+ */
33
+ export declare interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
34
+ isOldest(): boolean;
35
+ }
36
+
37
+ /**
38
+ * Events emitted by {@link IOldestClientObservable}.
39
+ * @alpha
40
+ */
41
+ export declare interface IOldestClientObserverEvents extends IEvent {
42
+ (event: "becameOldest" | "lostOldest", listener: () => void): any;
43
+ }
44
+
45
+ /**
46
+ * The `OldestClientObserver` is a utility inspect if the local client is the oldest amongst connected clients (in
47
+ * terms of when they connected) and watch for changes.
48
+ *
49
+ * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.
50
+ *
51
+ * @remarks
52
+ * ### Creation
53
+ *
54
+ * The `OldestClientObserver` constructor takes an `IOldestClientObservable`. This is most easily satisfied with
55
+ * either an `IContainerRuntime` or an `IFluidDataStoreRuntime`:
56
+ *
57
+ * ```typescript
58
+ * // E.g. from within a BaseContainerRuntimeFactory:
59
+ * protected async containerHasInitialized(runtime: IContainerRuntime) {
60
+ * const oldestClientObserver = new OldestClientObserver(runtime);
61
+ * // ...
62
+ * }
63
+ * ```
64
+ *
65
+ * ```typescript
66
+ * // From within a DataObject
67
+ * protected async hasInitialized() {
68
+ * const oldestClientObserver = new OldestClientObserver(this.runtime);
69
+ * // ...
70
+ * }
71
+ * ```
72
+ *
73
+ * ### Usage
74
+ *
75
+ * To check if the local client is the oldest, use the `isOldest()` method.
76
+ *
77
+ * ```typescript
78
+ * if (oldestClientObserver.isOldest()) {
79
+ * console.log("I'm the oldest");
80
+ * } else {
81
+ * console.log("Someone else is older");
82
+ * }
83
+ * ```
84
+ *
85
+ * ### Eventing
86
+ *
87
+ * `OldestClientObserver` is an `EventEmitter`, and will emit events when the local client becomes the oldest and when
88
+ * it is no longer the oldest.
89
+ *
90
+ * ```typescript
91
+ * oldestClientObserver.on("becameOldest", () => {
92
+ * console.log("I'm the oldest now");
93
+ * });
94
+ *
95
+ * oldestClientObserver.on("lostOldest", () => {
96
+ * console.log("I'm not the oldest anymore");
97
+ * });
98
+ * ```
99
+ * @alpha
100
+ */
101
+ export declare class OldestClientObserver extends TypedEventEmitter<IOldestClientObserverEvents> implements IOldestClientObserver {
102
+ private readonly observable;
103
+ private readonly quorum;
104
+ private currentIsOldest;
105
+ constructor(observable: IOldestClientObservable);
106
+ isOldest(): boolean;
107
+ private readonly updateOldest;
108
+ private computeIsOldest;
109
+ }
110
+
111
+ export { }
@@ -58,7 +58,7 @@ import { IOldestClientObservable, IOldestClientObserverEvents, IOldestClientObse
58
58
  * console.log("I'm not the oldest anymore");
59
59
  * });
60
60
  * ```
61
- * @internal
61
+ * @alpha
62
62
  */
63
63
  export declare class OldestClientObserver extends TypedEventEmitter<IOldestClientObserverEvents> implements IOldestClientObserver {
64
64
  private readonly observable;
@@ -69,4 +69,4 @@ export declare class OldestClientObserver extends TypedEventEmitter<IOldestClien
69
69
  private readonly updateOldest;
70
70
  private computeIsOldest;
71
71
  }
72
- //# sourceMappingURL=oldestClientObserver.d.ts.map
72
+ //# sourceMappingURL=oldestClientObserver.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oldestClientObserver.d.mts","sourceRoot":"","sources":["../src/oldestClientObserver.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EAAE,iBAAiB,EAAE,MAAM,8BAA8B;OAIzD,EACN,uBAAuB,EACvB,2BAA2B,EAC3B,qBAAqB,EACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,qBAAa,oBACZ,SAAQ,iBAAiB,CAAC,2BAA2B,CACrD,YAAW,qBAAqB;IAIpB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAFvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,eAAe,CAAkB;gBACZ,UAAU,EAAE,uBAAuB;IAUzD,QAAQ,IAAI,OAAO;IAI1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAU3B;IAEF,OAAO,CAAC,eAAe;CAkCvB"}
@@ -59,7 +59,7 @@ import { AttachState } from "@fluidframework/container-definitions";
59
59
  * console.log("I'm not the oldest anymore");
60
60
  * });
61
61
  * ```
62
- * @internal
62
+ * @alpha
63
63
  */
64
64
  export class OldestClientObserver extends TypedEventEmitter {
65
65
  constructor(observable) {
@@ -1 +1 @@
1
- {"version":3,"file":"oldestClientObserver.mjs","sourceRoot":"","sources":["../src/oldestClientObserver.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EAAE,iBAAiB,EAAE,MAAM,8BAA8B;OACzD,EAAE,MAAM,EAAE,MAAM,4BAA4B;OAC5C,EAAE,WAAW,EAAE,MAAM,uCAAuC;AAQnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAM,OAAO,oBACZ,SAAQ,iBAA8C;IAKtD,YAA6B,UAAmC;QAC/D,KAAK,EAAE,CAAC;QADoB,eAAU,GAAV,UAAU,CAAyB;QADxD,oBAAe,GAAY,KAAK,CAAC;QAexB,iBAAY,GAAG,GAAS,EAAE;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,eAAe,KAAK,MAAM,EAAE;gBACpC,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC;gBAC9B,IAAI,MAAM,EAAE;oBACX,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;iBAC1B;qBAAM;oBACN,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;iBACxB;aACD;QACF,CAAC,CAAC;QAtBD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9C,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAcO,eAAe;QACtB,uGAAuG;QACvG,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,WAAW,CAAC,QAAQ,EAAE;YACzD,OAAO,IAAI,CAAC;SACZ;QAED,kEAAkE;QAClE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE;YAC/B,OAAO,KAAK,CAAC;SACb;QAED,yDAAyD;QACzD,MAAM,CACL,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS;QACtC,4DAA4D;QAC5D,KAAK,CAAC,4CAA4C,CAClD,CAAC;QAEF,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC5E,wEAAwE;QACxE,IAAI,mBAAmB,KAAK,SAAS,EAAE;YACtC,OAAO,KAAK,CAAC;SACb;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACzC,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE;YAC/C,IAAI,eAAe,CAAC,cAAc,GAAG,mBAAmB,CAAC,cAAc,EAAE;gBACxE,OAAO,KAAK,CAAC;aACb;SACD;QAED,oCAAoC;QACpC,OAAO,IAAI,CAAC;IACb,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\nimport {\n\tIOldestClientObservable,\n\tIOldestClientObserverEvents,\n\tIOldestClientObserver,\n} from \"./interfaces\";\n\n/**\n * The `OldestClientObserver` is a utility inspect if the local client is the oldest amongst connected clients (in\n * terms of when they connected) and watch for changes.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * The `OldestClientObserver` constructor takes an `IOldestClientObservable`. This is most easily satisfied with\n * either an `IContainerRuntime` or an `IFluidDataStoreRuntime`:\n *\n * ```typescript\n * // E.g. from within a BaseContainerRuntimeFactory:\n * protected async containerHasInitialized(runtime: IContainerRuntime) {\n * const oldestClientObserver = new OldestClientObserver(runtime);\n * // ...\n * }\n * ```\n *\n * ```typescript\n * // From within a DataObject\n * protected async hasInitialized() {\n * const oldestClientObserver = new OldestClientObserver(this.runtime);\n * // ...\n * }\n * ```\n *\n * ### Usage\n *\n * To check if the local client is the oldest, use the `isOldest()` method.\n *\n * ```typescript\n * if (oldestClientObserver.isOldest()) {\n * console.log(\"I'm the oldest\");\n * } else {\n * console.log(\"Someone else is older\");\n * }\n * ```\n *\n * ### Eventing\n *\n * `OldestClientObserver` is an `EventEmitter`, and will emit events when the local client becomes the oldest and when\n * it is no longer the oldest.\n *\n * ```typescript\n * oldestClientObserver.on(\"becameOldest\", () => {\n * console.log(\"I'm the oldest now\");\n * });\n *\n * oldestClientObserver.on(\"lostOldest\", () => {\n * console.log(\"I'm not the oldest anymore\");\n * });\n * ```\n * @internal\n */\nexport class OldestClientObserver\n\textends TypedEventEmitter<IOldestClientObserverEvents>\n\timplements IOldestClientObserver\n{\n\tprivate readonly quorum: IQuorumClients;\n\tprivate currentIsOldest: boolean = false;\n\tconstructor(private readonly observable: IOldestClientObservable) {\n\t\tsuper();\n\t\tthis.quorum = this.observable.getQuorum();\n\t\tthis.currentIsOldest = this.computeIsOldest();\n\t\tthis.quorum.on(\"addMember\", this.updateOldest);\n\t\tthis.quorum.on(\"removeMember\", this.updateOldest);\n\t\tobservable.on(\"connected\", this.updateOldest);\n\t\tobservable.on(\"disconnected\", this.updateOldest);\n\t}\n\n\tpublic isOldest(): boolean {\n\t\treturn this.currentIsOldest;\n\t}\n\n\tprivate readonly updateOldest = (): void => {\n\t\tconst oldest = this.computeIsOldest();\n\t\tif (this.currentIsOldest !== oldest) {\n\t\t\tthis.currentIsOldest = oldest;\n\t\t\tif (oldest) {\n\t\t\t\tthis.emit(\"becameOldest\");\n\t\t\t} else {\n\t\t\t\tthis.emit(\"lostOldest\");\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate computeIsOldest(): boolean {\n\t\t// If the container is detached, we are the only ones that know about it and are the oldest by default.\n\t\tif (this.observable.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// If we're not connected we can't be the oldest connected client.\n\t\tif (!this.observable.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\t\tassert(\n\t\t\tthis.observable.clientId !== undefined,\n\t\t\t// eslint-disable-next-line unicorn/numeric-separators-style\n\t\t\t0x1da /* \"Client id should be set if connected\" */,\n\t\t);\n\n\t\tconst selfSequencedClient = this.quorum.getMember(this.observable.clientId);\n\t\t// When in readonly mode our clientId will not be present in the quorum.\n\t\tif (selfSequencedClient === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst members = this.quorum.getMembers();\n\t\tfor (const sequencedClient of members.values()) {\n\t\t\tif (sequencedClient.sequenceNumber < selfSequencedClient.sequenceNumber) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// No member of the quorum was older\n\t\treturn true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"oldestClientObserver.mjs","sourceRoot":"","sources":["../src/oldestClientObserver.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EAAE,iBAAiB,EAAE,MAAM,8BAA8B;OACzD,EAAE,MAAM,EAAE,MAAM,4BAA4B;OAC5C,EAAE,WAAW,EAAE,MAAM,uCAAuC;AAQnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAM,OAAO,oBACZ,SAAQ,iBAA8C;IAKtD,YAA6B,UAAmC;QAC/D,KAAK,EAAE,CAAC;QADoB,eAAU,GAAV,UAAU,CAAyB;QADxD,oBAAe,GAAY,KAAK,CAAC;QAexB,iBAAY,GAAG,GAAS,EAAE;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,eAAe,KAAK,MAAM,EAAE;gBACpC,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC;gBAC9B,IAAI,MAAM,EAAE;oBACX,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;iBAC1B;qBAAM;oBACN,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;iBACxB;aACD;QACF,CAAC,CAAC;QAtBD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9C,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAcO,eAAe;QACtB,uGAAuG;QACvG,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,WAAW,CAAC,QAAQ,EAAE;YACzD,OAAO,IAAI,CAAC;SACZ;QAED,kEAAkE;QAClE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE;YAC/B,OAAO,KAAK,CAAC;SACb;QAED,yDAAyD;QACzD,MAAM,CACL,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS;QACtC,4DAA4D;QAC5D,KAAK,CAAC,4CAA4C,CAClD,CAAC;QAEF,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC5E,wEAAwE;QACxE,IAAI,mBAAmB,KAAK,SAAS,EAAE;YACtC,OAAO,KAAK,CAAC;SACb;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACzC,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE;YAC/C,IAAI,eAAe,CAAC,cAAc,GAAG,mBAAmB,CAAC,cAAc,EAAE;gBACxE,OAAO,KAAK,CAAC;aACb;SACD;QAED,oCAAoC;QACpC,OAAO,IAAI,CAAC;IACb,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\nimport {\n\tIOldestClientObservable,\n\tIOldestClientObserverEvents,\n\tIOldestClientObserver,\n} from \"./interfaces\";\n\n/**\n * The `OldestClientObserver` is a utility inspect if the local client is the oldest amongst connected clients (in\n * terms of when they connected) and watch for changes.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * The `OldestClientObserver` constructor takes an `IOldestClientObservable`. This is most easily satisfied with\n * either an `IContainerRuntime` or an `IFluidDataStoreRuntime`:\n *\n * ```typescript\n * // E.g. from within a BaseContainerRuntimeFactory:\n * protected async containerHasInitialized(runtime: IContainerRuntime) {\n * const oldestClientObserver = new OldestClientObserver(runtime);\n * // ...\n * }\n * ```\n *\n * ```typescript\n * // From within a DataObject\n * protected async hasInitialized() {\n * const oldestClientObserver = new OldestClientObserver(this.runtime);\n * // ...\n * }\n * ```\n *\n * ### Usage\n *\n * To check if the local client is the oldest, use the `isOldest()` method.\n *\n * ```typescript\n * if (oldestClientObserver.isOldest()) {\n * console.log(\"I'm the oldest\");\n * } else {\n * console.log(\"Someone else is older\");\n * }\n * ```\n *\n * ### Eventing\n *\n * `OldestClientObserver` is an `EventEmitter`, and will emit events when the local client becomes the oldest and when\n * it is no longer the oldest.\n *\n * ```typescript\n * oldestClientObserver.on(\"becameOldest\", () => {\n * console.log(\"I'm the oldest now\");\n * });\n *\n * oldestClientObserver.on(\"lostOldest\", () => {\n * console.log(\"I'm not the oldest anymore\");\n * });\n * ```\n * @alpha\n */\nexport class OldestClientObserver\n\textends TypedEventEmitter<IOldestClientObserverEvents>\n\timplements IOldestClientObserver\n{\n\tprivate readonly quorum: IQuorumClients;\n\tprivate currentIsOldest: boolean = false;\n\tconstructor(private readonly observable: IOldestClientObservable) {\n\t\tsuper();\n\t\tthis.quorum = this.observable.getQuorum();\n\t\tthis.currentIsOldest = this.computeIsOldest();\n\t\tthis.quorum.on(\"addMember\", this.updateOldest);\n\t\tthis.quorum.on(\"removeMember\", this.updateOldest);\n\t\tobservable.on(\"connected\", this.updateOldest);\n\t\tobservable.on(\"disconnected\", this.updateOldest);\n\t}\n\n\tpublic isOldest(): boolean {\n\t\treturn this.currentIsOldest;\n\t}\n\n\tprivate readonly updateOldest = (): void => {\n\t\tconst oldest = this.computeIsOldest();\n\t\tif (this.currentIsOldest !== oldest) {\n\t\t\tthis.currentIsOldest = oldest;\n\t\t\tif (oldest) {\n\t\t\t\tthis.emit(\"becameOldest\");\n\t\t\t} else {\n\t\t\t\tthis.emit(\"lostOldest\");\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate computeIsOldest(): boolean {\n\t\t// If the container is detached, we are the only ones that know about it and are the oldest by default.\n\t\tif (this.observable.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// If we're not connected we can't be the oldest connected client.\n\t\tif (!this.observable.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\t\tassert(\n\t\t\tthis.observable.clientId !== undefined,\n\t\t\t// eslint-disable-next-line unicorn/numeric-separators-style\n\t\t\t0x1da /* \"Client id should be set if connected\" */,\n\t\t);\n\n\t\tconst selfSequencedClient = this.quorum.getMember(this.observable.clientId);\n\t\t// When in readonly mode our clientId will not be present in the quorum.\n\t\tif (selfSequencedClient === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst members = this.quorum.getMembers();\n\t\tfor (const sequencedClient of members.values()) {\n\t\t\tif (sequencedClient.sequenceNumber < selfSequencedClient.sequenceNumber) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// No member of the quorum was older\n\t\treturn true;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-experimental/oldest-client-observer",
3
- "version": "2.0.0-internal.8.0.0",
3
+ "version": "2.0.0-rc.1.0.0",
4
4
  "description": "Data object to determine if the local client is the oldest amongst connected clients",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -11,20 +11,72 @@
11
11
  "license": "MIT",
12
12
  "author": "Microsoft and contributors",
13
13
  "sideEffects": false,
14
- "main": "dist/index.cjs",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./lib/index.d.mts",
18
+ "default": "./lib/index.mjs"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "./alpha": {
26
+ "import": {
27
+ "types": "./lib/oldest-client-observer-alpha.d.mts",
28
+ "default": "./lib/index.mjs"
29
+ },
30
+ "require": {
31
+ "types": "./dist/oldest-client-observer-alpha.d.ts",
32
+ "default": "./dist/index.js"
33
+ }
34
+ },
35
+ "./beta": {
36
+ "import": {
37
+ "types": "./lib/oldest-client-observer-beta.d.mts",
38
+ "default": "./lib/index.mjs"
39
+ },
40
+ "require": {
41
+ "types": "./dist/oldest-client-observer-beta.d.ts",
42
+ "default": "./dist/index.js"
43
+ }
44
+ },
45
+ "./internal": {
46
+ "import": {
47
+ "types": "./lib/index.d.mts",
48
+ "default": "./lib/index.mjs"
49
+ },
50
+ "require": {
51
+ "types": "./dist/index.d.ts",
52
+ "default": "./dist/index.js"
53
+ }
54
+ },
55
+ "./public": {
56
+ "import": {
57
+ "types": "./lib/oldest-client-observer-public.d.mts",
58
+ "default": "./lib/index.mjs"
59
+ },
60
+ "require": {
61
+ "types": "./dist/oldest-client-observer-public.d.ts",
62
+ "default": "./dist/index.js"
63
+ }
64
+ }
65
+ },
66
+ "main": "dist/index.js",
15
67
  "module": "lib/index.mjs",
16
68
  "types": "dist/index.d.ts",
17
69
  "c8": {
18
70
  "all": true,
19
71
  "cache-dir": "nyc/.cache",
20
72
  "exclude": [
21
- "src/test/**/*.ts",
22
- "dist/test/**/*.js"
73
+ "src/test/**/*.*ts",
74
+ "dist/test/**/*.*js"
23
75
  ],
24
76
  "exclude-after-remap": false,
25
77
  "include": [
26
- "src/**/*.ts",
27
- "dist/**/*.js"
78
+ "src/**/*.*ts",
79
+ "dist/**/*.*js"
28
80
  ],
29
81
  "report-dir": "nyc/report",
30
82
  "reporter": [
@@ -35,19 +87,20 @@
35
87
  "temp-directory": "nyc/.nyc_output"
36
88
  },
37
89
  "dependencies": {
38
- "@fluid-internal/client-utils": ">=2.0.0-internal.8.0.0 <2.0.0-internal.8.1.0",
39
- "@fluidframework/container-definitions": ">=2.0.0-internal.8.0.0 <2.0.0-internal.8.1.0",
40
- "@fluidframework/core-interfaces": ">=2.0.0-internal.8.0.0 <2.0.0-internal.8.1.0",
41
- "@fluidframework/core-utils": ">=2.0.0-internal.8.0.0 <2.0.0-internal.8.1.0",
42
- "@fluidframework/protocol-definitions": "^3.0.0"
90
+ "@fluid-internal/client-utils": ">=2.0.0-rc.1.0.0 <2.0.0-rc.1.1.0",
91
+ "@fluidframework/container-definitions": ">=2.0.0-rc.1.0.0 <2.0.0-rc.1.1.0",
92
+ "@fluidframework/core-interfaces": ">=2.0.0-rc.1.0.0 <2.0.0-rc.1.1.0",
93
+ "@fluidframework/core-utils": ">=2.0.0-rc.1.0.0 <2.0.0-rc.1.1.0",
94
+ "@fluidframework/protocol-definitions": "^3.1.0"
43
95
  },
44
96
  "devDependencies": {
45
- "@fluid-private/test-dds-utils": ">=2.0.0-internal.8.0.0 <2.0.0-internal.8.1.0",
46
- "@fluid-tools/build-cli": "^0.28.0",
97
+ "@arethetypeswrong/cli": "^0.13.3",
98
+ "@fluid-private/test-dds-utils": ">=2.0.0-rc.1.0.0 <2.0.0-rc.1.1.0",
99
+ "@fluid-tools/build-cli": "^0.29.0",
47
100
  "@fluidframework/build-common": "^2.0.3",
48
- "@fluidframework/build-tools": "^0.28.0",
49
- "@fluidframework/eslint-config-fluid": "^3.1.0",
50
- "@fluidframework/test-runtime-utils": ">=2.0.0-internal.8.0.0 <2.0.0-internal.8.1.0",
101
+ "@fluidframework/build-tools": "^0.29.0",
102
+ "@fluidframework/eslint-config-fluid": "^3.2.0",
103
+ "@fluidframework/test-runtime-utils": ">=2.0.0-rc.1.0.0 <2.0.0-rc.1.1.0",
51
104
  "@microsoft/api-extractor": "^7.38.3",
52
105
  "@types/node": "^18.19.0",
53
106
  "copyfiles": "^2.4.1",
@@ -81,12 +134,13 @@
81
134
  "scripts": {
82
135
  "api": "fluid-build . --task api",
83
136
  "api-extractor:commonjs": "api-extractor run --local",
84
- "api-extractor:esnext": "copyfiles -u 1 \"dist/**/*-@(alpha|beta|public|untrimmed).d.ts\" lib",
137
+ "api-extractor:esnext": "api-extractor run --config ./api-extractor-esm.json",
85
138
  "build": "fluid-build . --task build",
86
139
  "build:commonjs": "fluid-build . --task commonjs",
87
140
  "build:compile": "fluid-build . --task compile",
88
141
  "build:docs": "fluid-build . --task api",
89
142
  "build:esnext": "tsc-multi --config ../../../common/build/build-common/tsc-multi.esm.json",
143
+ "check:are-the-types-wrong": "attw --pack . --entrypoints .",
90
144
  "check:release-tags": "api-extractor run --local --config ./api-extractor-lint.json",
91
145
  "ci:build:docs": "api-extractor run",
92
146
  "clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp",
@@ -97,7 +151,7 @@
97
151
  "lint:fix": "npm run prettier:fix && npm run eslint:fix",
98
152
  "prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore",
99
153
  "prettier:fix": "prettier --write . --cache --ignore-path ../../../.prettierignore",
100
- "tsc": "tsc-multi --config ../../../common/build/build-common/tsc-multi.cjs.json",
154
+ "tsc": "tsc",
101
155
  "typetests:gen": "fluid-type-test-generator",
102
156
  "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
103
157
  }
package/src/interfaces.ts CHANGED
@@ -9,7 +9,7 @@ import { IQuorumClients } from "@fluidframework/protocol-definitions";
9
9
 
10
10
  /**
11
11
  * Events emitted by {@link IOldestClientObservable}.
12
- * @internal
12
+ * @alpha
13
13
  */
14
14
  export interface IOldestClientObservableEvents extends IEvent {
15
15
  (event: "connected", listener: () => void);
@@ -21,7 +21,7 @@ export interface IOldestClientObservableEvents extends IEvent {
21
21
  * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,
22
22
  * since neither is really the source of truth (they are just the only currently-available plumbing options).
23
23
  * It's information about the connection, so the real source of truth is lower (at the connection layer).
24
- * @internal
24
+ * @alpha
25
25
  */
26
26
  export interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {
27
27
  getQuorum(): IQuorumClients;
@@ -37,14 +37,14 @@ export interface IOldestClientObservable extends IEventProvider<IOldestClientObs
37
37
 
38
38
  /**
39
39
  * Events emitted by {@link IOldestClientObservable}.
40
- * @internal
40
+ * @alpha
41
41
  */
42
42
  export interface IOldestClientObserverEvents extends IEvent {
43
43
  (event: "becameOldest" | "lostOldest", listener: () => void);
44
44
  }
45
45
 
46
46
  /**
47
- * @internal
47
+ * @alpha
48
48
  */
49
49
  export interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {
50
50
  isOldest(): boolean;
@@ -67,7 +67,7 @@ import {
67
67
  * console.log("I'm not the oldest anymore");
68
68
  * });
69
69
  * ```
70
- * @internal
70
+ * @alpha
71
71
  */
72
72
  export class OldestClientObserver
73
73
  extends TypedEventEmitter<IOldestClientObserverEvents>
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,mEAA8D;AAArD,4HAAA,oBAAoB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tIOldestClientObservable,\n\tIOldestClientObservableEvents,\n\tIOldestClientObserver,\n\tIOldestClientObserverEvents,\n} from \"./interfaces\";\nexport { OldestClientObserver } from \"./oldestClientObserver\";\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"interfaces.cjs","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IEvent, IEventProvider } from \"@fluidframework/core-interfaces\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @internal\n */\nexport interface IOldestClientObservableEvents extends IEvent {\n\t(event: \"connected\", listener: () => void);\n\t(event: \"disconnected\", listener: () => void);\n}\n\n/**\n * This is to make OldestClientObserver work with either a ContainerRuntime or an IFluidDataStoreRuntime\n * (both expose the relevant API surface and eventing). However, really this info probably shouldn't live on either,\n * since neither is really the source of truth (they are just the only currently-available plumbing options).\n * It's information about the connection, so the real source of truth is lower (at the connection layer).\n * @internal\n */\nexport interface IOldestClientObservable extends IEventProvider<IOldestClientObservableEvents> {\n\tgetQuorum(): IQuorumClients;\n\t// Generic usage of attachState is a little unusual here. We will treat ourselves as \"the oldest client that\n\t// has information about this [container | data store]\", which in the case of detached data store may disagree\n\t// with whether we're the oldest client on the connected container. So in the data store case, it's only\n\t// safe use this as an indicator about rights to tasks performed against this specific data store, and not\n\t// more broadly.\n\tattachState: AttachState;\n\tconnected: boolean;\n\tclientId: string | undefined;\n}\n\n/**\n * Events emitted by {@link IOldestClientObservable}.\n * @internal\n */\nexport interface IOldestClientObserverEvents extends IEvent {\n\t(event: \"becameOldest\" | \"lostOldest\", listener: () => void);\n}\n\n/**\n * @internal\n */\nexport interface IOldestClientObserver extends IEventProvider<IOldestClientObserverEvents> {\n\tisOldest(): boolean;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"oldestClientObserver.cjs","sourceRoot":"","sources":["../src/oldestClientObserver.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;AACjE,2DAAoD;AACpD,iFAAoE;AAQpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAa,oBACZ,SAAQ,gCAA8C;IAKtD,YAA6B,UAAmC;QAC/D,KAAK,EAAE,CAAC;QADoB,eAAU,GAAV,UAAU,CAAyB;QADxD,oBAAe,GAAY,KAAK,CAAC;QAexB,iBAAY,GAAG,GAAS,EAAE;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,eAAe,KAAK,MAAM,EAAE;gBACpC,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC;gBAC9B,IAAI,MAAM,EAAE;oBACX,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;iBAC1B;qBAAM;oBACN,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;iBACxB;aACD;QACF,CAAC,CAAC;QAtBD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9C,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAcO,eAAe;QACtB,uGAAuG;QACvG,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,mCAAW,CAAC,QAAQ,EAAE;YACzD,OAAO,IAAI,CAAC;SACZ;QAED,kEAAkE;QAClE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE;YAC/B,OAAO,KAAK,CAAC;SACb;QAED,yDAAyD;QACzD,IAAA,mBAAM,EACL,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS;QACtC,4DAA4D;QAC5D,KAAK,CAAC,4CAA4C,CAClD,CAAC;QAEF,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC5E,wEAAwE;QACxE,IAAI,mBAAmB,KAAK,SAAS,EAAE;YACtC,OAAO,KAAK,CAAC;SACb;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACzC,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE;YAC/C,IAAI,eAAe,CAAC,cAAc,GAAG,mBAAmB,CAAC,cAAc,EAAE;gBACxE,OAAO,KAAK,CAAC;aACb;SACD;QAED,oCAAoC;QACpC,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAlED,oDAkEC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IQuorumClients } from \"@fluidframework/protocol-definitions\";\nimport {\n\tIOldestClientObservable,\n\tIOldestClientObserverEvents,\n\tIOldestClientObserver,\n} from \"./interfaces\";\n\n/**\n * The `OldestClientObserver` is a utility inspect if the local client is the oldest amongst connected clients (in\n * terms of when they connected) and watch for changes.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * The `OldestClientObserver` constructor takes an `IOldestClientObservable`. This is most easily satisfied with\n * either an `IContainerRuntime` or an `IFluidDataStoreRuntime`:\n *\n * ```typescript\n * // E.g. from within a BaseContainerRuntimeFactory:\n * protected async containerHasInitialized(runtime: IContainerRuntime) {\n * const oldestClientObserver = new OldestClientObserver(runtime);\n * // ...\n * }\n * ```\n *\n * ```typescript\n * // From within a DataObject\n * protected async hasInitialized() {\n * const oldestClientObserver = new OldestClientObserver(this.runtime);\n * // ...\n * }\n * ```\n *\n * ### Usage\n *\n * To check if the local client is the oldest, use the `isOldest()` method.\n *\n * ```typescript\n * if (oldestClientObserver.isOldest()) {\n * console.log(\"I'm the oldest\");\n * } else {\n * console.log(\"Someone else is older\");\n * }\n * ```\n *\n * ### Eventing\n *\n * `OldestClientObserver` is an `EventEmitter`, and will emit events when the local client becomes the oldest and when\n * it is no longer the oldest.\n *\n * ```typescript\n * oldestClientObserver.on(\"becameOldest\", () => {\n * console.log(\"I'm the oldest now\");\n * });\n *\n * oldestClientObserver.on(\"lostOldest\", () => {\n * console.log(\"I'm not the oldest anymore\");\n * });\n * ```\n * @internal\n */\nexport class OldestClientObserver\n\textends TypedEventEmitter<IOldestClientObserverEvents>\n\timplements IOldestClientObserver\n{\n\tprivate readonly quorum: IQuorumClients;\n\tprivate currentIsOldest: boolean = false;\n\tconstructor(private readonly observable: IOldestClientObservable) {\n\t\tsuper();\n\t\tthis.quorum = this.observable.getQuorum();\n\t\tthis.currentIsOldest = this.computeIsOldest();\n\t\tthis.quorum.on(\"addMember\", this.updateOldest);\n\t\tthis.quorum.on(\"removeMember\", this.updateOldest);\n\t\tobservable.on(\"connected\", this.updateOldest);\n\t\tobservable.on(\"disconnected\", this.updateOldest);\n\t}\n\n\tpublic isOldest(): boolean {\n\t\treturn this.currentIsOldest;\n\t}\n\n\tprivate readonly updateOldest = (): void => {\n\t\tconst oldest = this.computeIsOldest();\n\t\tif (this.currentIsOldest !== oldest) {\n\t\t\tthis.currentIsOldest = oldest;\n\t\t\tif (oldest) {\n\t\t\t\tthis.emit(\"becameOldest\");\n\t\t\t} else {\n\t\t\t\tthis.emit(\"lostOldest\");\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate computeIsOldest(): boolean {\n\t\t// If the container is detached, we are the only ones that know about it and are the oldest by default.\n\t\tif (this.observable.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// If we're not connected we can't be the oldest connected client.\n\t\tif (!this.observable.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\t\tassert(\n\t\t\tthis.observable.clientId !== undefined,\n\t\t\t// eslint-disable-next-line unicorn/numeric-separators-style\n\t\t\t0x1da /* \"Client id should be set if connected\" */,\n\t\t);\n\n\t\tconst selfSequencedClient = this.quorum.getMember(this.observable.clientId);\n\t\t// When in readonly mode our clientId will not be present in the quorum.\n\t\tif (selfSequencedClient === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst members = this.quorum.getMembers();\n\t\tfor (const sequencedClient of members.values()) {\n\t\t\tif (sequencedClient.sequenceNumber < selfSequencedClient.sequenceNumber) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// No member of the quorum was older\n\t\treturn true;\n\t}\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EACN,uBAAuB,EACvB,6BAA6B,EAC7B,qBAAqB,EACrB,2BAA2B,GAC3B;OACM,EAAE,oBAAoB,EAAE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,iCAAiC;OACjE,EAAE,WAAW,EAAE,MAAM,uCAAuC;OAC5D,EAAE,cAAc,EAAE,MAAM,sCAAsC;AAErE;;;GAGG;AACH,MAAM,WAAW,6BAA8B,SAAQ,MAAM;IAC5D,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;IAC3C,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CAC9C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,uBAAwB,SAAQ,cAAc,CAAC,6BAA6B,CAAC;IAC7F,SAAS,IAAI,cAAc,CAAC;IAM5B,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA4B,SAAQ,MAAM;IAC1D,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CAC7D;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,cAAc,CAAC,2BAA2B,CAAC;IACzF,QAAQ,IAAI,OAAO,CAAC;CACpB"}
@@ -1,25 +0,0 @@
1
- import { AttachState } from '@fluidframework/container-definitions';
2
- import { IEvent } from '@fluidframework/core-interfaces';
3
- import { IEventProvider } from '@fluidframework/core-interfaces';
4
- import { IQuorumClients } from '@fluidframework/protocol-definitions';
5
- import { TypedEventEmitter } from '@fluid-internal/client-utils';
6
-
7
- /* Excluded from this release type: AttachState */
8
-
9
- /* Excluded from this release type: IEvent */
10
-
11
- /* Excluded from this release type: IEventProvider */
12
-
13
- /* Excluded from this release type: IOldestClientObservable */
14
-
15
- /* Excluded from this release type: IOldestClientObservableEvents */
16
-
17
- /* Excluded from this release type: IOldestClientObserver */
18
-
19
- /* Excluded from this release type: IOldestClientObserverEvents */
20
-
21
- /* Excluded from this release type: OldestClientObserver */
22
-
23
- /* Excluded from this release type: TypedEventEmitter */
24
-
25
- export { }
@@ -1 +0,0 @@
1
- {"version":3,"file":"oldestClientObserver.d.ts","sourceRoot":"","sources":["../src/oldestClientObserver.ts"],"names":[],"mappings":"AAAA;;;GAGG;OAEI,EAAE,iBAAiB,EAAE,MAAM,8BAA8B;OAIzD,EACN,uBAAuB,EACvB,2BAA2B,EAC3B,qBAAqB,EACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,qBAAa,oBACZ,SAAQ,iBAAiB,CAAC,2BAA2B,CACrD,YAAW,qBAAqB;IAIpB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAFvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,eAAe,CAAkB;gBACZ,UAAU,EAAE,uBAAuB;IAUzD,QAAQ,IAAI,OAAO;IAI1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAU3B;IAEF,OAAO,CAAC,eAAe;CAkCvB"}