@fluidframework/presence 2.10.0 → 2.12.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.
- package/README.md +37 -2
- package/dist/alpha.d.ts +1 -1
- package/dist/exposedUtilityTypes.d.ts +5 -5
- package/dist/exposedUtilityTypes.d.ts.map +1 -1
- package/dist/exposedUtilityTypes.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/latestMapValueManager.d.ts +2 -2
- package/dist/latestMapValueManager.d.ts.map +1 -1
- package/dist/latestMapValueManager.js +2 -2
- package/dist/latestMapValueManager.js.map +1 -1
- package/dist/latestValueManager.d.ts +2 -2
- package/dist/latestValueManager.d.ts.map +1 -1
- package/dist/latestValueManager.js +2 -2
- package/dist/latestValueManager.js.map +1 -1
- package/dist/notificationsManager.d.ts +28 -15
- package/dist/notificationsManager.d.ts.map +1 -1
- package/dist/notificationsManager.js +3 -5
- package/dist/notificationsManager.js.map +1 -1
- package/dist/package.json +0 -1
- package/dist/presence.d.ts +2 -2
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js.map +1 -1
- package/dist/presenceDatastoreManager.d.ts +14 -1
- package/dist/presenceDatastoreManager.d.ts.map +1 -1
- package/dist/presenceDatastoreManager.js +96 -18
- package/dist/presenceDatastoreManager.js.map +1 -1
- package/dist/presenceManager.d.ts.map +1 -1
- package/dist/presenceManager.js +2 -2
- package/dist/presenceManager.js.map +1 -1
- package/dist/presenceStates.d.ts +6 -0
- package/dist/presenceStates.d.ts.map +1 -1
- package/dist/presenceStates.js +7 -1
- package/dist/presenceStates.js.map +1 -1
- package/dist/systemWorkspace.d.ts +1 -1
- package/dist/systemWorkspace.d.ts.map +1 -1
- package/dist/systemWorkspace.js.map +1 -1
- package/dist/timerManager.d.ts +37 -0
- package/dist/timerManager.d.ts.map +1 -0
- package/dist/timerManager.js +65 -0
- package/dist/timerManager.js.map +1 -0
- package/lib/alpha.d.ts +1 -1
- package/lib/exposedUtilityTypes.d.ts +5 -5
- package/lib/exposedUtilityTypes.d.ts.map +1 -1
- package/lib/exposedUtilityTypes.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/latestMapValueManager.d.ts +2 -2
- package/lib/latestMapValueManager.d.ts.map +1 -1
- package/lib/latestMapValueManager.js +1 -1
- package/lib/latestMapValueManager.js.map +1 -1
- package/lib/latestValueManager.d.ts +2 -2
- package/lib/latestValueManager.d.ts.map +1 -1
- package/lib/latestValueManager.js +1 -1
- package/lib/latestValueManager.js.map +1 -1
- package/lib/notificationsManager.d.ts +28 -15
- package/lib/notificationsManager.d.ts.map +1 -1
- package/lib/notificationsManager.js +2 -4
- package/lib/notificationsManager.js.map +1 -1
- package/lib/presence.d.ts +2 -2
- package/lib/presence.d.ts.map +1 -1
- package/lib/presence.js.map +1 -1
- package/lib/presenceDatastoreManager.d.ts +14 -1
- package/lib/presenceDatastoreManager.d.ts.map +1 -1
- package/lib/presenceDatastoreManager.js +97 -19
- package/lib/presenceDatastoreManager.js.map +1 -1
- package/lib/presenceManager.d.ts.map +1 -1
- package/lib/presenceManager.js +1 -1
- package/lib/presenceManager.js.map +1 -1
- package/lib/presenceStates.d.ts +6 -0
- package/lib/presenceStates.d.ts.map +1 -1
- package/lib/presenceStates.js +6 -1
- package/lib/presenceStates.js.map +1 -1
- package/lib/systemWorkspace.d.ts +1 -1
- package/lib/systemWorkspace.d.ts.map +1 -1
- package/lib/systemWorkspace.js.map +1 -1
- package/lib/timerManager.d.ts +37 -0
- package/lib/timerManager.d.ts.map +1 -0
- package/lib/timerManager.js +61 -0
- package/lib/timerManager.js.map +1 -0
- package/package.json +21 -25
- package/dist/events/events.d.ts +0 -198
- package/dist/events/events.d.ts.map +0 -1
- package/dist/events/events.js +0 -157
- package/dist/events/events.js.map +0 -1
- package/lib/events/events.d.ts +0 -198
- package/lib/events/events.d.ts.map +0 -1
- package/lib/events/events.js +0 -152
- package/lib/events/events.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/presence",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "A component for lightweight data sharing within a single session",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -31,10 +31,6 @@
|
|
|
31
31
|
"import": "./lib/core-interfaces/index.js",
|
|
32
32
|
"require": "./dist/core-interfaces/index.js"
|
|
33
33
|
},
|
|
34
|
-
"./internal/events": {
|
|
35
|
-
"import": "./lib/events/events.js",
|
|
36
|
-
"require": "./dist/events/events.js"
|
|
37
|
-
},
|
|
38
34
|
"./internal/exposedInternalTypes": {
|
|
39
35
|
"import": "./lib/exposedInternalTypes.js",
|
|
40
36
|
"require": "./dist/exposedInternalTypes.js"
|
|
@@ -73,31 +69,31 @@
|
|
|
73
69
|
"temp-directory": "nyc/.nyc_output"
|
|
74
70
|
},
|
|
75
71
|
"dependencies": {
|
|
76
|
-
"@
|
|
77
|
-
"@fluidframework/container-
|
|
78
|
-
"@fluidframework/container-
|
|
79
|
-
"@fluidframework/
|
|
80
|
-
"@fluidframework/core-
|
|
81
|
-
"@fluidframework/
|
|
82
|
-
"@fluidframework/datastore
|
|
83
|
-
"@fluidframework/
|
|
84
|
-
"@fluidframework/
|
|
85
|
-
"@fluidframework/
|
|
86
|
-
"@fluidframework/runtime-
|
|
87
|
-
"@fluidframework/
|
|
88
|
-
"@fluidframework/
|
|
72
|
+
"@fluid-internal/client-utils": "~2.12.0",
|
|
73
|
+
"@fluidframework/container-definitions": "~2.12.0",
|
|
74
|
+
"@fluidframework/container-loader": "~2.12.0",
|
|
75
|
+
"@fluidframework/container-runtime-definitions": "~2.12.0",
|
|
76
|
+
"@fluidframework/core-interfaces": "~2.12.0",
|
|
77
|
+
"@fluidframework/core-utils": "~2.12.0",
|
|
78
|
+
"@fluidframework/datastore": "~2.12.0",
|
|
79
|
+
"@fluidframework/datastore-definitions": "~2.12.0",
|
|
80
|
+
"@fluidframework/fluid-static": "~2.12.0",
|
|
81
|
+
"@fluidframework/id-compressor": "~2.12.0",
|
|
82
|
+
"@fluidframework/runtime-definitions": "~2.12.0",
|
|
83
|
+
"@fluidframework/runtime-utils": "~2.12.0",
|
|
84
|
+
"@fluidframework/shared-object-base": "~2.12.0",
|
|
85
|
+
"@fluidframework/telemetry-utils": "~2.12.0"
|
|
89
86
|
},
|
|
90
87
|
"devDependencies": {
|
|
91
|
-
"@arethetypeswrong/cli": "^0.
|
|
88
|
+
"@arethetypeswrong/cli": "^0.17.1",
|
|
92
89
|
"@biomejs/biome": "~1.9.3",
|
|
93
90
|
"@fluid-tools/build-cli": "^0.51.0",
|
|
94
91
|
"@fluidframework/build-common": "^2.0.3",
|
|
95
92
|
"@fluidframework/build-tools": "^0.51.0",
|
|
96
|
-
"@fluidframework/driver-definitions": "~2.
|
|
97
|
-
"@fluidframework/eslint-config-fluid": "^5.
|
|
98
|
-
"@fluidframework/
|
|
99
|
-
"@fluidframework/test-
|
|
100
|
-
"@fluidframework/test-utils": "~2.10.0",
|
|
93
|
+
"@fluidframework/driver-definitions": "~2.12.0",
|
|
94
|
+
"@fluidframework/eslint-config-fluid": "^5.6.0",
|
|
95
|
+
"@fluidframework/test-runtime-utils": "~2.12.0",
|
|
96
|
+
"@fluidframework/test-utils": "~2.12.0",
|
|
101
97
|
"@microsoft/api-extractor": "7.47.8",
|
|
102
98
|
"@types/mocha": "^9.1.1",
|
|
103
99
|
"@types/node": "^18.19.0",
|
|
@@ -146,7 +142,7 @@
|
|
|
146
142
|
"build:test:cjs": "fluid-tsc commonjs --project ./src/test/tsconfig.cjs.json",
|
|
147
143
|
"build:test:esm": "tsc --project ./src/test/tsconfig.json",
|
|
148
144
|
"build:test:esm:core-interfaces-no-exactOptionalPropertyTypes": "tsc --project ./src/test/core-interfaces/tsconfig.no-exactOptionalPropertyTypes.json",
|
|
149
|
-
"check:are-the-types-wrong": "
|
|
145
|
+
"check:are-the-types-wrong": "attw --pack . --profile node16",
|
|
150
146
|
"check:biome": "biome check .",
|
|
151
147
|
"check:exports": "concurrently \"npm:check:exports:*\"",
|
|
152
148
|
"check:exports:bundle-release-tags": "api-extractor run --config api-extractor/api-extractor-lint-bundle.json",
|
package/dist/events/events.d.ts
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* This file is a clone of the `events.ts` file from the `@fluidframework/tree` package.
|
|
7
|
-
* `@public` APIs have been changed to `@alpha` and some lint defects from more strict rules
|
|
8
|
-
* have been fixed or suppressed.
|
|
9
|
-
*/
|
|
10
|
-
import type { IEvent } from "@fluidframework/core-interfaces";
|
|
11
|
-
/**
|
|
12
|
-
* Convert a union of types to an intersection of those types. Useful for `TransformEvents`.
|
|
13
|
-
*/
|
|
14
|
-
export type UnionToIntersection<T> = (T extends any ? (k: T) => unknown : never) extends (k: infer U) => unknown ? U : never;
|
|
15
|
-
/**
|
|
16
|
-
* `true` iff the given type is an acceptable shape for an event
|
|
17
|
-
* @alpha
|
|
18
|
-
*/
|
|
19
|
-
export type IsEvent<Event> = Event extends (...args: any[]) => any ? true : false;
|
|
20
|
-
/**
|
|
21
|
-
* Used to specify the kinds of events emitted by an {@link ISubscribable}.
|
|
22
|
-
*
|
|
23
|
-
* @remarks
|
|
24
|
-
*
|
|
25
|
-
* Any object type is a valid {@link Events}, but only the event-like properties of that
|
|
26
|
-
* type will be included.
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
*
|
|
30
|
-
* ```typescript
|
|
31
|
-
* interface MyEvents {
|
|
32
|
-
* load: (user: string, data: IUserData) => void;
|
|
33
|
-
* error: (errorCode: number) => void;
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* @alpha
|
|
38
|
-
*/
|
|
39
|
-
export type Events<E> = {
|
|
40
|
-
[P in (string | symbol) & keyof E as IsEvent<E[P]> extends true ? P : never]: E[P];
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* Converts an `Events` type (i.e. the event registry for an {@link ISubscribable}) into a type consumable
|
|
44
|
-
* by an IEventProvider from `@fluidframework/core-interfaces`.
|
|
45
|
-
* @param E - the `Events` type to transform
|
|
46
|
-
* @param Target - an optional `IEvent` type that will be merged into the result along with the transformed `E`
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
*
|
|
50
|
-
* ```typescript
|
|
51
|
-
* interface MyEvents {
|
|
52
|
-
* load: (user: string, data: IUserData) => void;
|
|
53
|
-
* error: (errorCode: number) => void;
|
|
54
|
-
* }
|
|
55
|
-
*
|
|
56
|
-
* class MySharedObject extends SharedObject<TransformEvents<MyEvents, ISharedObjectEvents>> {
|
|
57
|
-
* // ...
|
|
58
|
-
* }
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
export type TransformEvents<E extends Events<E>, Target extends IEvent = IEvent> = {
|
|
62
|
-
[P in keyof Events<E>]: (event: P, listener: E[P]) => void;
|
|
63
|
-
} extends Record<any, infer Z> ? UnionToIntersection<Z> & Target : never;
|
|
64
|
-
/**
|
|
65
|
-
* An object which allows the registration of listeners so that subscribers can be notified when an event happens.
|
|
66
|
-
*
|
|
67
|
-
* `EventEmitter` can be used as a base class to implement this via extension.
|
|
68
|
-
* @param E - All the events that this emitter supports
|
|
69
|
-
* @example
|
|
70
|
-
* ```ts
|
|
71
|
-
* type MyEventEmitter = IEventEmitter<{
|
|
72
|
-
* load: (user: string, data: IUserData) => void;
|
|
73
|
-
* error: (errorCode: number) => void;
|
|
74
|
-
* }>
|
|
75
|
-
* ```
|
|
76
|
-
* @privateRemarks
|
|
77
|
-
* {@link createEmitter} can help implement this interface via delegation.
|
|
78
|
-
*
|
|
79
|
-
* @alpha
|
|
80
|
-
*/
|
|
81
|
-
export interface ISubscribable<E extends Events<E>> {
|
|
82
|
-
/**
|
|
83
|
-
* Register an event listener.
|
|
84
|
-
* @param eventName - the name of the event
|
|
85
|
-
* @param listener - the handler to run when the event is fired by the emitter
|
|
86
|
-
* @returns a function which will deregister the listener when run. This function has undefined behavior
|
|
87
|
-
* if called more than once.
|
|
88
|
-
*/
|
|
89
|
-
on<K extends keyof Events<E>>(eventName: K, listener: E[K]): () => void;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Interface for an event emitter that can emit typed events to subscribed listeners.
|
|
93
|
-
* @internal
|
|
94
|
-
*/
|
|
95
|
-
export interface IEmitter<E extends Events<E>> {
|
|
96
|
-
/**
|
|
97
|
-
* Emits an event with the specified name and arguments, notifying all subscribers by calling their registered listener functions.
|
|
98
|
-
* @param eventName - the name of the event to fire
|
|
99
|
-
* @param args - the arguments passed to the event listener functions
|
|
100
|
-
*/
|
|
101
|
-
emit<K extends keyof Events<E>>(eventName: K, ...args: Parameters<E[K]>): void;
|
|
102
|
-
/**
|
|
103
|
-
* Emits an event with the specified name and arguments, notifying all subscribers by calling their registered listener functions.
|
|
104
|
-
* It also collects the return values of all listeners into an array.
|
|
105
|
-
*
|
|
106
|
-
* Warning: This method should be used with caution. It deviates from the standard event-based integration pattern as creates substantial coupling between the emitter and its listeners.
|
|
107
|
-
* For the majority of use-cases it is recommended to use the standard {@link IEmitter.emit} functionality.
|
|
108
|
-
* @param eventName - the name of the event to fire
|
|
109
|
-
* @param args - the arguments passed to the event listener functions
|
|
110
|
-
* @returns An array of the return values of each listener, preserving the order listeners were called.
|
|
111
|
-
*/
|
|
112
|
-
emitAndCollect<K extends keyof Events<E>>(eventName: K, ...args: Parameters<E[K]>): ReturnType<E[K]>[];
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Create an {@link ISubscribable} that can be instructed to emit events via the {@link IEmitter} interface.
|
|
116
|
-
*
|
|
117
|
-
* A class can delegate handling {@link ISubscribable} to the returned value while using it to emit the events.
|
|
118
|
-
* See also `EventEmitter` which be used as a base class to implement {@link ISubscribable} via extension.
|
|
119
|
-
* @internal
|
|
120
|
-
*/
|
|
121
|
-
export declare function createEmitter<E extends Events<E>>(noListeners?: NoListenersCallback<E>): ISubscribable<E> & IEmitter<E> & HasListeners<E>;
|
|
122
|
-
/**
|
|
123
|
-
* Called when the last listener for `eventName` is removed.
|
|
124
|
-
* Useful for determining when to clean up resources related to detecting when the event might occurs.
|
|
125
|
-
* @internal
|
|
126
|
-
*/
|
|
127
|
-
export type NoListenersCallback<E extends Events<E>> = (eventName: keyof Events<E>) => void;
|
|
128
|
-
/**
|
|
129
|
-
* @internal
|
|
130
|
-
*/
|
|
131
|
-
export interface HasListeners<E extends Events<E>> {
|
|
132
|
-
/**
|
|
133
|
-
* When no `eventName` is provided, returns true iff there are any listeners.
|
|
134
|
-
*
|
|
135
|
-
* When `eventName` is provided, returns true iff there are listeners for that event.
|
|
136
|
-
*
|
|
137
|
-
* @remarks
|
|
138
|
-
* This can be used to know when its safe to cleanup data-structures which only exist to fire events for their listeners.
|
|
139
|
-
*/
|
|
140
|
-
hasListeners(eventName?: keyof Events<E>): boolean;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Provides an API for subscribing to and listening to events.
|
|
144
|
-
*
|
|
145
|
-
* @remarks Classes wishing to emit events may either extend this class or compose over it.
|
|
146
|
-
*
|
|
147
|
-
* @example Extending this class
|
|
148
|
-
*
|
|
149
|
-
* ```typescript
|
|
150
|
-
* interface MyEvents {
|
|
151
|
-
* "loaded": () => void;
|
|
152
|
-
* }
|
|
153
|
-
*
|
|
154
|
-
* class MyClass extends EventEmitter<MyEvents> {
|
|
155
|
-
* private load() {
|
|
156
|
-
* this.emit("loaded");
|
|
157
|
-
* }
|
|
158
|
-
* }
|
|
159
|
-
* ```
|
|
160
|
-
*
|
|
161
|
-
* @example Composing over this class
|
|
162
|
-
*
|
|
163
|
-
* ```typescript
|
|
164
|
-
* class MyClass implements ISubscribable<MyEvents> {
|
|
165
|
-
* private readonly events = EventEmitter.create<MyEvents>();
|
|
166
|
-
*
|
|
167
|
-
* private load() {
|
|
168
|
-
* this.events.emit("loaded");
|
|
169
|
-
* }
|
|
170
|
-
*
|
|
171
|
-
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
|
|
172
|
-
* return this.events.on(eventName, listener);
|
|
173
|
-
* }
|
|
174
|
-
* }
|
|
175
|
-
* ```
|
|
176
|
-
*/
|
|
177
|
-
export declare class EventEmitter<E extends Events<E>> implements ISubscribable<E>, HasListeners<E> {
|
|
178
|
-
private readonly noListeners?;
|
|
179
|
-
private readonly listeners;
|
|
180
|
-
protected constructor(noListeners?: NoListenersCallback<E> | undefined);
|
|
181
|
-
protected emit<K extends keyof Events<E>>(eventName: K, ...args: Parameters<E[K]>): void;
|
|
182
|
-
protected emitAndCollect<K extends keyof Events<E>>(eventName: K, ...args: Parameters<E[K]>): ReturnType<E[K]>[];
|
|
183
|
-
/**
|
|
184
|
-
* Register an event listener.
|
|
185
|
-
* @param eventName - the name of the event
|
|
186
|
-
* @param listener - the handler to run when the event is fired by the emitter
|
|
187
|
-
* @returns a function which will deregister the listener when run.
|
|
188
|
-
* This function will error if called more than once.
|
|
189
|
-
* @privateRemarks
|
|
190
|
-
* TODO:
|
|
191
|
-
* invoking the returned callback can error even if its only called once if the same listener was provided to two calls to "on".
|
|
192
|
-
* This behavior is not documented and its unclear if its a bug or not: see note on listeners.
|
|
193
|
-
*/
|
|
194
|
-
on<K extends keyof Events<E>>(eventName: K, listener: E[K]): () => void;
|
|
195
|
-
private off;
|
|
196
|
-
hasListeners(eventName?: keyof Events<E>): boolean;
|
|
197
|
-
}
|
|
198
|
-
//# sourceMappingURL=events.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/events/events.ts"],"names":[],"mappings":"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"}
|
package/dist/events/events.js
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*!
|
|
3
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
-
* Licensed under the MIT License.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.EventEmitter = exports.createEmitter = void 0;
|
|
8
|
-
const internal_1 = require("@fluidframework/core-utils/internal");
|
|
9
|
-
function fail(message) {
|
|
10
|
-
throw new Error(message);
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.
|
|
14
|
-
* @param map - The map to query/update
|
|
15
|
-
* @param key - The key to lookup in the map
|
|
16
|
-
* @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists
|
|
17
|
-
* @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)
|
|
18
|
-
*/
|
|
19
|
-
function getOrCreate(map, key, defaultValue) {
|
|
20
|
-
let value = map.get(key);
|
|
21
|
-
if (value === undefined) {
|
|
22
|
-
value = defaultValue(key);
|
|
23
|
-
map.set(key, value);
|
|
24
|
-
}
|
|
25
|
-
return value;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Create an {@link ISubscribable} that can be instructed to emit events via the {@link IEmitter} interface.
|
|
29
|
-
*
|
|
30
|
-
* A class can delegate handling {@link ISubscribable} to the returned value while using it to emit the events.
|
|
31
|
-
* See also `EventEmitter` which be used as a base class to implement {@link ISubscribable} via extension.
|
|
32
|
-
* @internal
|
|
33
|
-
*/
|
|
34
|
-
function createEmitter(noListeners) {
|
|
35
|
-
return new ComposableEventEmitter(noListeners);
|
|
36
|
-
}
|
|
37
|
-
exports.createEmitter = createEmitter;
|
|
38
|
-
/**
|
|
39
|
-
* Provides an API for subscribing to and listening to events.
|
|
40
|
-
*
|
|
41
|
-
* @remarks Classes wishing to emit events may either extend this class or compose over it.
|
|
42
|
-
*
|
|
43
|
-
* @example Extending this class
|
|
44
|
-
*
|
|
45
|
-
* ```typescript
|
|
46
|
-
* interface MyEvents {
|
|
47
|
-
* "loaded": () => void;
|
|
48
|
-
* }
|
|
49
|
-
*
|
|
50
|
-
* class MyClass extends EventEmitter<MyEvents> {
|
|
51
|
-
* private load() {
|
|
52
|
-
* this.emit("loaded");
|
|
53
|
-
* }
|
|
54
|
-
* }
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* @example Composing over this class
|
|
58
|
-
*
|
|
59
|
-
* ```typescript
|
|
60
|
-
* class MyClass implements ISubscribable<MyEvents> {
|
|
61
|
-
* private readonly events = EventEmitter.create<MyEvents>();
|
|
62
|
-
*
|
|
63
|
-
* private load() {
|
|
64
|
-
* this.events.emit("loaded");
|
|
65
|
-
* }
|
|
66
|
-
*
|
|
67
|
-
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
|
|
68
|
-
* return this.events.on(eventName, listener);
|
|
69
|
-
* }
|
|
70
|
-
* }
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
class EventEmitter {
|
|
74
|
-
// Because this is protected and not public, calling this externally (not from a subclass) makes sending events to the constructed instance impossible.
|
|
75
|
-
// Instead, use the static `create` function to get an instance which allows emitting events.
|
|
76
|
-
constructor(noListeners) {
|
|
77
|
-
this.noListeners = noListeners;
|
|
78
|
-
// TODO: because the inner data-structure here is a set, adding the same callback twice does not error,
|
|
79
|
-
// but only calls it once, and unsubscribing will stop calling it all together.
|
|
80
|
-
// This is surprising since it makes subscribing and unsubscribing not inverses (but instead both idempotent).
|
|
81
|
-
// This might be desired, but if so the documentation should indicate it.
|
|
82
|
-
this.listeners = new Map();
|
|
83
|
-
}
|
|
84
|
-
emit(eventName, ...args) {
|
|
85
|
-
const listeners = this.listeners.get(eventName);
|
|
86
|
-
if (listeners !== undefined) {
|
|
87
|
-
const argArray = args; // TODO: Current TS (4.5.5) cannot spread `args` into `listener()`, but future versions (e.g. 4.8.4) can.
|
|
88
|
-
// This explicitly copies listeners so that new listeners added during this call to emit will not receive this event.
|
|
89
|
-
for (const listener of listeners) {
|
|
90
|
-
// If listener has been unsubscribed while invoking other listeners, skip it.
|
|
91
|
-
if (listeners.has(listener)) {
|
|
92
|
-
listener(...argArray);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
emitAndCollect(eventName, ...args) {
|
|
98
|
-
const listeners = this.listeners.get(eventName);
|
|
99
|
-
if (listeners !== undefined) {
|
|
100
|
-
const argArray = args;
|
|
101
|
-
const resultArray = [];
|
|
102
|
-
for (const listener of listeners.values()) {
|
|
103
|
-
// listner return type is any to enable this.listeners to be a Map
|
|
104
|
-
// of Sets rather than a Record with tracked (known) return types.
|
|
105
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
106
|
-
resultArray.push(listener(...argArray));
|
|
107
|
-
}
|
|
108
|
-
return resultArray;
|
|
109
|
-
}
|
|
110
|
-
return [];
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Register an event listener.
|
|
114
|
-
* @param eventName - the name of the event
|
|
115
|
-
* @param listener - the handler to run when the event is fired by the emitter
|
|
116
|
-
* @returns a function which will deregister the listener when run.
|
|
117
|
-
* This function will error if called more than once.
|
|
118
|
-
* @privateRemarks
|
|
119
|
-
* TODO:
|
|
120
|
-
* invoking the returned callback can error even if its only called once if the same listener was provided to two calls to "on".
|
|
121
|
-
* This behavior is not documented and its unclear if its a bug or not: see note on listeners.
|
|
122
|
-
*/
|
|
123
|
-
on(eventName, listener) {
|
|
124
|
-
getOrCreate(this.listeners, eventName, () => new Set()).add(listener);
|
|
125
|
-
return () => this.off(eventName, listener);
|
|
126
|
-
}
|
|
127
|
-
off(eventName, listener) {
|
|
128
|
-
const listeners = this.listeners.get(eventName) ??
|
|
129
|
-
// TODO: consider making this (and assert below) a usage error since it can be triggered by users of the public API: maybe separate those use cases somehow?
|
|
130
|
-
fail("Event has no listeners. Event deregistration functions may only be invoked once.");
|
|
131
|
-
(0, internal_1.assert)(listeners.delete(listener), 0xa30 /* Listener does not exist. Event deregistration functions may only be invoked once. */);
|
|
132
|
-
if (listeners.size === 0) {
|
|
133
|
-
this.listeners.delete(eventName);
|
|
134
|
-
this.noListeners?.(eventName);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
hasListeners(eventName) {
|
|
138
|
-
if (eventName === undefined) {
|
|
139
|
-
return this.listeners.size > 0;
|
|
140
|
-
}
|
|
141
|
-
return this.listeners.has(eventName);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
exports.EventEmitter = EventEmitter;
|
|
145
|
-
// This class exposes the constructor and the `emit` method of `EventEmitter`, elevating them from protected to public
|
|
146
|
-
class ComposableEventEmitter extends EventEmitter {
|
|
147
|
-
constructor(noListeners) {
|
|
148
|
-
super(noListeners);
|
|
149
|
-
}
|
|
150
|
-
emit(eventName, ...args) {
|
|
151
|
-
return super.emit(eventName, ...args);
|
|
152
|
-
}
|
|
153
|
-
emitAndCollect(eventName, ...args) {
|
|
154
|
-
return super.emitAndCollect(eventName, ...args);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
//# sourceMappingURL=events.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/events/events.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * This file is a clone of the `events.ts` file from the `@fluidframework/tree` package.\n * `@public` APIs have been changed to `@alpha` and some lint defects from more strict rules\n * have been fixed or suppressed.\n */\n\nimport type { IEvent } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nfunction fail(message: string): never {\n\tthrow new Error(message);\n}\n\n/**\n * Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.\n * @param map - The map to query/update\n * @param key - The key to lookup in the map\n * @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists\n * @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)\n */\nfunction getOrCreate<K, V>(map: Map<K, V>, key: K, defaultValue: (key: K) => V): V {\n\tlet value = map.get(key);\n\tif (value === undefined) {\n\t\tvalue = defaultValue(key);\n\t\tmap.set(key, value);\n\t}\n\treturn value;\n}\n\n/**\n * Convert a union of types to an intersection of those types. Useful for `TransformEvents`.\n */\nexport type UnionToIntersection<T> = (T extends any ? (k: T) => unknown : never) extends (\n\tk: infer U,\n) => unknown\n\t? U\n\t: never;\n\n/**\n * `true` iff the given type is an acceptable shape for an event\n * @alpha\n */\nexport type IsEvent<Event> = Event extends (...args: any[]) => any ? true : false;\n\n/**\n * Used to specify the kinds of events emitted by an {@link ISubscribable}.\n *\n * @remarks\n *\n * Any object type is a valid {@link Events}, but only the event-like properties of that\n * type will be included.\n *\n * @example\n *\n * ```typescript\n * interface MyEvents {\n * load: (user: string, data: IUserData) => void;\n * error: (errorCode: number) => void;\n * }\n * ```\n *\n * @alpha\n */\nexport type Events<E> = {\n\t[P in (string | symbol) & keyof E as IsEvent<E[P]> extends true ? P : never]: E[P];\n};\n\n/**\n * Converts an `Events` type (i.e. the event registry for an {@link ISubscribable}) into a type consumable\n * by an IEventProvider from `@fluidframework/core-interfaces`.\n * @param E - the `Events` type to transform\n * @param Target - an optional `IEvent` type that will be merged into the result along with the transformed `E`\n *\n * @example\n *\n * ```typescript\n * interface MyEvents {\n * load: (user: string, data: IUserData) => void;\n * error: (errorCode: number) => void;\n * }\n *\n * class MySharedObject extends SharedObject<TransformEvents<MyEvents, ISharedObjectEvents>> {\n * // ...\n * }\n * ```\n */\nexport type TransformEvents<E extends Events<E>, Target extends IEvent = IEvent> = {\n\t[P in keyof Events<E>]: (event: P, listener: E[P]) => void;\n} extends Record<any, infer Z>\n\t? UnionToIntersection<Z> & Target\n\t: never;\n\n/**\n * An object which allows the registration of listeners so that subscribers can be notified when an event happens.\n *\n * `EventEmitter` can be used as a base class to implement this via extension.\n * @param E - All the events that this emitter supports\n * @example\n * ```ts\n * type MyEventEmitter = IEventEmitter<{\n * load: (user: string, data: IUserData) => void;\n * error: (errorCode: number) => void;\n * }>\n * ```\n * @privateRemarks\n * {@link createEmitter} can help implement this interface via delegation.\n *\n * @alpha\n */\nexport interface ISubscribable<E extends Events<E>> {\n\t/**\n\t * Register an event listener.\n\t * @param eventName - the name of the event\n\t * @param listener - the handler to run when the event is fired by the emitter\n\t * @returns a function which will deregister the listener when run. This function has undefined behavior\n\t * if called more than once.\n\t */\n\ton<K extends keyof Events<E>>(eventName: K, listener: E[K]): () => void;\n}\n\n/**\n * Interface for an event emitter that can emit typed events to subscribed listeners.\n * @internal\n */\nexport interface IEmitter<E extends Events<E>> {\n\t/**\n\t * Emits an event with the specified name and arguments, notifying all subscribers by calling their registered listener functions.\n\t * @param eventName - the name of the event to fire\n\t * @param args - the arguments passed to the event listener functions\n\t */\n\temit<K extends keyof Events<E>>(eventName: K, ...args: Parameters<E[K]>): void;\n\n\t/**\n\t * Emits an event with the specified name and arguments, notifying all subscribers by calling their registered listener functions.\n\t * It also collects the return values of all listeners into an array.\n\t *\n\t * Warning: This method should be used with caution. It deviates from the standard event-based integration pattern as creates substantial coupling between the emitter and its listeners.\n\t * For the majority of use-cases it is recommended to use the standard {@link IEmitter.emit} functionality.\n\t * @param eventName - the name of the event to fire\n\t * @param args - the arguments passed to the event listener functions\n\t * @returns An array of the return values of each listener, preserving the order listeners were called.\n\t */\n\temitAndCollect<K extends keyof Events<E>>(\n\t\teventName: K,\n\t\t...args: Parameters<E[K]>\n\t): ReturnType<E[K]>[];\n}\n\n/**\n * Create an {@link ISubscribable} that can be instructed to emit events via the {@link IEmitter} interface.\n *\n * A class can delegate handling {@link ISubscribable} to the returned value while using it to emit the events.\n * See also `EventEmitter` which be used as a base class to implement {@link ISubscribable} via extension.\n * @internal\n */\nexport function createEmitter<E extends Events<E>>(\n\tnoListeners?: NoListenersCallback<E>,\n): ISubscribable<E> & IEmitter<E> & HasListeners<E> {\n\treturn new ComposableEventEmitter<E>(noListeners);\n}\n\n/**\n * Called when the last listener for `eventName` is removed.\n * Useful for determining when to clean up resources related to detecting when the event might occurs.\n * @internal\n */\nexport type NoListenersCallback<E extends Events<E>> = (eventName: keyof Events<E>) => void;\n\n/**\n * @internal\n */\nexport interface HasListeners<E extends Events<E>> {\n\t/**\n\t * When no `eventName` is provided, returns true iff there are any listeners.\n\t *\n\t * When `eventName` is provided, returns true iff there are listeners for that event.\n\t *\n\t * @remarks\n\t * This can be used to know when its safe to cleanup data-structures which only exist to fire events for their listeners.\n\t */\n\thasListeners(eventName?: keyof Events<E>): boolean;\n}\n\n/**\n * Provides an API for subscribing to and listening to events.\n *\n * @remarks Classes wishing to emit events may either extend this class or compose over it.\n *\n * @example Extending this class\n *\n * ```typescript\n * interface MyEvents {\n * \"loaded\": () => void;\n * }\n *\n * class MyClass extends EventEmitter<MyEvents> {\n * private load() {\n * this.emit(\"loaded\");\n * }\n * }\n * ```\n *\n * @example Composing over this class\n *\n * ```typescript\n * class MyClass implements ISubscribable<MyEvents> {\n * private readonly events = EventEmitter.create<MyEvents>();\n *\n * private load() {\n * this.events.emit(\"loaded\");\n * }\n *\n * public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {\n * return this.events.on(eventName, listener);\n * }\n * }\n * ```\n */\nexport class EventEmitter<E extends Events<E>> implements ISubscribable<E>, HasListeners<E> {\n\t// TODO: because the inner data-structure here is a set, adding the same callback twice does not error,\n\t// but only calls it once, and unsubscribing will stop calling it all together.\n\t// This is surprising since it makes subscribing and unsubscribing not inverses (but instead both idempotent).\n\t// This might be desired, but if so the documentation should indicate it.\n\tprivate readonly listeners = new Map<keyof E, Set<(...args: unknown[]) => any>>();\n\n\t// Because this is protected and not public, calling this externally (not from a subclass) makes sending events to the constructed instance impossible.\n\t// Instead, use the static `create` function to get an instance which allows emitting events.\n\tprotected constructor(private readonly noListeners?: NoListenersCallback<E>) {}\n\n\tprotected emit<K extends keyof Events<E>>(eventName: K, ...args: Parameters<E[K]>): void {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners !== undefined) {\n\t\t\tconst argArray: unknown[] = args; // TODO: Current TS (4.5.5) cannot spread `args` into `listener()`, but future versions (e.g. 4.8.4) can.\n\t\t\t// This explicitly copies listeners so that new listeners added during this call to emit will not receive this event.\n\t\t\tfor (const listener of listeners) {\n\t\t\t\t// If listener has been unsubscribed while invoking other listeners, skip it.\n\t\t\t\tif (listeners.has(listener)) {\n\t\t\t\t\tlistener(...argArray);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected emitAndCollect<K extends keyof Events<E>>(\n\t\teventName: K,\n\t\t...args: Parameters<E[K]>\n\t): ReturnType<E[K]>[] {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners !== undefined) {\n\t\t\tconst argArray: unknown[] = args;\n\t\t\tconst resultArray: ReturnType<E[K]>[] = [];\n\t\t\tfor (const listener of listeners.values()) {\n\t\t\t\t// listner return type is any to enable this.listeners to be a Map\n\t\t\t\t// of Sets rather than a Record with tracked (known) return types.\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t\t\t\tresultArray.push(listener(...argArray));\n\t\t\t}\n\t\t\treturn resultArray;\n\t\t}\n\t\treturn [];\n\t}\n\n\t/**\n\t * Register an event listener.\n\t * @param eventName - the name of the event\n\t * @param listener - the handler to run when the event is fired by the emitter\n\t * @returns a function which will deregister the listener when run.\n\t * This function will error if called more than once.\n\t * @privateRemarks\n\t * TODO:\n\t * invoking the returned callback can error even if its only called once if the same listener was provided to two calls to \"on\".\n\t * This behavior is not documented and its unclear if its a bug or not: see note on listeners.\n\t */\n\tpublic on<K extends keyof Events<E>>(eventName: K, listener: E[K]): () => void {\n\t\tgetOrCreate(this.listeners, eventName, () => new Set()).add(listener);\n\t\treturn () => this.off(eventName, listener);\n\t}\n\n\tprivate off<K extends keyof Events<E>>(eventName: K, listener: E[K]): void {\n\t\tconst listeners =\n\t\t\tthis.listeners.get(eventName) ??\n\t\t\t// TODO: consider making this (and assert below) a usage error since it can be triggered by users of the public API: maybe separate those use cases somehow?\n\t\t\tfail(\"Event has no listeners. Event deregistration functions may only be invoked once.\");\n\t\tassert(\n\t\t\tlisteners.delete(listener),\n\t\t\t0xa30 /* Listener does not exist. Event deregistration functions may only be invoked once. */,\n\t\t);\n\t\tif (listeners.size === 0) {\n\t\t\tthis.listeners.delete(eventName);\n\t\t\tthis.noListeners?.(eventName);\n\t\t}\n\t}\n\n\tpublic hasListeners(eventName?: keyof Events<E>): boolean {\n\t\tif (eventName === undefined) {\n\t\t\treturn this.listeners.size > 0;\n\t\t}\n\t\treturn this.listeners.has(eventName);\n\t}\n}\n\n// This class exposes the constructor and the `emit` method of `EventEmitter`, elevating them from protected to public\nclass ComposableEventEmitter<E extends Events<E>>\n\textends EventEmitter<E>\n\timplements IEmitter<E>\n{\n\tpublic constructor(noListeners?: NoListenersCallback<E>) {\n\t\tsuper(noListeners);\n\t}\n\n\tpublic override emit<K extends keyof Events<E>>(\n\t\teventName: K,\n\t\t...args: Parameters<E[K]>\n\t): void {\n\t\treturn super.emit(eventName, ...args);\n\t}\n\n\tpublic override emitAndCollect<K extends keyof Events<E>>(\n\t\teventName: K,\n\t\t...args: Parameters<E[K]>\n\t): ReturnType<E[K]>[] {\n\t\treturn super.emitAndCollect(eventName, ...args);\n\t}\n}\n"]}
|