@soundworks/core 4.0.0-alpha.9 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/README.md +14 -29
  3. package/package.json +24 -42
  4. package/src/client/Client.js +306 -256
  5. package/src/client/{Context.js → ClientContext.js} +63 -54
  6. package/src/client/ClientContextManager.js +115 -0
  7. package/src/client/{Plugin.js → ClientPlugin.js} +23 -19
  8. package/src/client/{PluginManager.js → ClientPluginManager.js} +43 -40
  9. package/src/client/ClientSocket.js +270 -0
  10. package/src/client/{StateManager.js → ClientStateManager.js} +13 -13
  11. package/src/client/index.js +36 -39
  12. package/src/common/BasePlugin.js +64 -58
  13. package/src/common/BasePluginManager.js +191 -142
  14. package/src/common/BaseStateManager.js +635 -145
  15. package/src/common/BatchedTransport.js +73 -0
  16. package/src/common/ParameterBag.js +90 -93
  17. package/src/common/PromiseStore.js +54 -0
  18. package/src/common/SharedState.js +821 -0
  19. package/src/common/SharedStateCollection.js +492 -0
  20. package/src/common/constants.js +14 -2
  21. package/src/common/logger.js +64 -68
  22. package/src/common/shared-state-types.js +82 -0
  23. package/src/common/sockets-utils.js +0 -64
  24. package/src/common/version.js +2 -0
  25. package/src/server/Server.js +552 -824
  26. package/src/server/ServerClient.js +74 -0
  27. package/src/server/{Context.js → ServerContext.js} +96 -77
  28. package/src/server/{ContextManager.js → ServerContextManager.js} +107 -87
  29. package/src/server/{Plugin.js → ServerPlugin.js} +30 -32
  30. package/src/server/ServerPluginManager.js +177 -0
  31. package/src/server/ServerSocket.js +256 -0
  32. package/src/server/ServerSockets.js +150 -0
  33. package/src/server/ServerStateManager.js +706 -0
  34. package/src/server/SharedStatePrivate.js +277 -0
  35. package/src/server/audit-network-latency.worker.js +19 -4
  36. package/src/server/{audit-schema.js → audit-state-class-description.js} +3 -2
  37. package/src/server/create-http-server.js +127 -0
  38. package/src/server/crypto.js +8 -7
  39. package/src/server/index.js +60 -17
  40. package/types/client/Client.d.ts +95 -70
  41. package/types/client/{Context.d.ts → ClientContext.d.ts} +59 -34
  42. package/types/client/{ContextManager.d.ts → ClientContextManager.d.ts} +19 -22
  43. package/types/client/ClientPlugin.d.ts +51 -0
  44. package/types/client/ClientPluginManager.d.ts +112 -0
  45. package/types/client/ClientSocket.d.ts +76 -0
  46. package/types/client/{StateManager.d.ts → ClientStateManager.d.ts} +18 -21
  47. package/types/client/index.d.ts +33 -6
  48. package/types/common/BasePlugin.d.ts +64 -53
  49. package/types/common/BasePluginManager.d.ts +84 -39
  50. package/types/common/BaseStateManager.d.ts +227 -49
  51. package/types/common/BatchedTransport.d.ts +17 -0
  52. package/types/common/ParameterBag.d.ts +73 -76
  53. package/types/common/PromiseStore.d.ts +11 -0
  54. package/types/common/SharedState.d.ts +291 -0
  55. package/types/common/SharedStateCollection.d.ts +311 -0
  56. package/types/common/constants.d.ts +10 -3
  57. package/types/common/logger.d.ts +8 -6
  58. package/types/common/shared-state-types.d.ts +95 -0
  59. package/types/common/sockets-utils.d.ts +0 -5
  60. package/types/common/version.d.ts +2 -0
  61. package/types/server/Server.d.ts +215 -136
  62. package/types/server/ServerClient.d.ts +45 -0
  63. package/types/server/ServerContext.d.ts +209 -0
  64. package/types/server/ServerContextManager.d.ts +75 -0
  65. package/types/server/ServerPlugin.d.ts +57 -0
  66. package/types/server/ServerPluginManager.d.ts +115 -0
  67. package/types/server/ServerSocket.d.ts +69 -0
  68. package/types/server/ServerSockets.d.ts +42 -0
  69. package/types/server/ServerStateManager.d.ts +284 -0
  70. package/types/server/SharedStatePrivate.d.ts +23 -0
  71. package/types/server/audit-network-latency.worker.d.ts +2 -2
  72. package/types/server/{audit-schema.d.ts → audit-state-class-description.d.ts} +8 -9
  73. package/types/server/create-http-server.d.ts +5 -0
  74. package/types/server/crypto.d.ts +4 -0
  75. package/types/server/index.d.ts +51 -3
  76. package/.eslintrc +0 -15
  77. package/.github/workflows/gh-pages.yml +0 -31
  78. package/.github/workflows/unit-tests.yml +0 -18
  79. package/src/client/ContextManager.js +0 -111
  80. package/src/client/SharedState.js +0 -84
  81. package/src/client/SharedStateCollection.js +0 -35
  82. package/src/client/Socket.js +0 -402
  83. package/src/common/BaseSharedState.js +0 -583
  84. package/src/common/BaseSharedStateCollection.js +0 -179
  85. package/src/common/SharedStatePrivate.js +0 -192
  86. package/src/common/promise-store.js +0 -25
  87. package/src/server/Client.js +0 -55
  88. package/src/server/PluginManager.js +0 -170
  89. package/src/server/SharedState.js +0 -85
  90. package/src/server/SharedStateCollection.js +0 -36
  91. package/src/server/Socket.js +0 -396
  92. package/src/server/Sockets.js +0 -224
  93. package/src/server/StateManager.js +0 -620
  94. package/tsconfig.json +0 -21
  95. package/types/client/Client.d.ts.map +0 -1
  96. package/types/client/Context.d.ts.map +0 -1
  97. package/types/client/ContextManager.d.ts.map +0 -1
  98. package/types/client/Plugin.d.ts +0 -53
  99. package/types/client/Plugin.d.ts.map +0 -1
  100. package/types/client/PluginManager.d.ts +0 -96
  101. package/types/client/PluginManager.d.ts.map +0 -1
  102. package/types/client/SharedState.d.ts +0 -85
  103. package/types/client/SharedState.d.ts.map +0 -1
  104. package/types/client/Socket.d.ts +0 -138
  105. package/types/client/Socket.d.ts.map +0 -1
  106. package/types/client/StateManager.d.ts.map +0 -1
  107. package/types/client/index.d.ts.map +0 -1
  108. package/types/common/BasePlugin.d.ts.map +0 -1
  109. package/types/common/BasePluginManager.d.ts.map +0 -1
  110. package/types/common/BaseSharedState.d.ts +0 -173
  111. package/types/common/BaseSharedState.d.ts.map +0 -1
  112. package/types/common/BaseStateManager.d.ts.map +0 -1
  113. package/types/common/ParameterBag.d.ts.map +0 -1
  114. package/types/common/SharedStatePrivate.d.ts +0 -20
  115. package/types/common/SharedStatePrivate.d.ts.map +0 -1
  116. package/types/common/constants.d.ts.map +0 -1
  117. package/types/common/logger.d.ts.map +0 -1
  118. package/types/common/promise-store.d.ts +0 -4
  119. package/types/common/promise-store.d.ts.map +0 -1
  120. package/types/common/sockets-utils.d.ts.map +0 -1
  121. package/types/common/utils.d.ts +0 -5
  122. package/types/common/utils.d.ts.map +0 -1
  123. package/types/server/Client.d.ts +0 -40
  124. package/types/server/Client.d.ts.map +0 -1
  125. package/types/server/Context.d.ts +0 -59
  126. package/types/server/Context.d.ts.map +0 -1
  127. package/types/server/ContextManager.d.ts +0 -69
  128. package/types/server/ContextManager.d.ts.map +0 -1
  129. package/types/server/Plugin.d.ts +0 -70
  130. package/types/server/Plugin.d.ts.map +0 -1
  131. package/types/server/PluginManager.d.ts +0 -91
  132. package/types/server/PluginManager.d.ts.map +0 -1
  133. package/types/server/Server.d.ts.map +0 -1
  134. package/types/server/SharedState.d.ts +0 -86
  135. package/types/server/SharedState.d.ts.map +0 -1
  136. package/types/server/Socket.d.ts +0 -128
  137. package/types/server/Socket.d.ts.map +0 -1
  138. package/types/server/Sockets.d.ts +0 -73
  139. package/types/server/Sockets.d.ts.map +0 -1
  140. package/types/server/StateManager.d.ts +0 -190
  141. package/types/server/StateManager.d.ts.map +0 -1
  142. package/types/server/audit-network-latency.worker.d.ts.map +0 -1
  143. package/types/server/audit-schema.d.ts.map +0 -1
  144. package/types/server/index.d.ts.map +0 -1
@@ -1,206 +1,273 @@
1
1
  import { isPlainObject, isString } from '@ircam/sc-utils';
2
2
 
3
+ import {
4
+ kBasePluginStatus,
5
+ } from './BasePlugin.js';
6
+
3
7
  import logger from './logger.js';
4
8
 
9
+ export const kPluginManagerStart = Symbol('soundworks:plugin-manager-start');
10
+ export const kPluginManagerStop = Symbol('soundworks:plugin-manager-stop');
11
+ export const kPluginManagerInstances = Symbol('soundworks:plugin-manager-instances');
12
+
5
13
  /**
6
- * Shared functionnality between server-side and client-size plugin manager
14
+ * Callback executed when a plugin internal state is updated.
7
15
  *
8
- * @private
16
+ * @callback pluginManagerOnStateChangeCallback
17
+ * @param {object<string, ClientPlugin|ServerPlugin>} fullState - List of all plugins.
18
+ * @param {ClientPlugin|ServerPlugin|null} initiator - Plugin that initiated the
19
+ * update. The value is `null` if the change was initiated by the state manager
20
+ * (e.g. when the initialization of the plugins starts).
9
21
  */
22
+
23
+ /**
24
+ * Delete the registered {@link pluginManagerOnStateChangeCallback}.
25
+ *
26
+ * @callback pluginManagerDeleteOnStateChangeCallback
27
+ */
28
+
29
+ /** @private */
10
30
  class BasePluginManager {
31
+ // node may be either the server or a client
32
+ #node = null;
33
+ #status = 'idle';
34
+ #dependencies = new Map();
35
+ #instanceStartPromises = new Map();
36
+ #onStateChangeCallbacks = new Set();
37
+
11
38
  constructor(node) {
12
- // node may be either a soundworks server or a soundworks client
13
- /** @private */
14
- this._node = node;
39
+ this.#node = node;
15
40
  /** @private */
16
- this._dependencies = new Map();
17
- /** @private */
18
- this._instances = new Map();
19
- /** @private */
20
- this._instanceStartPromises = new Map();
21
- /** @private */
22
- this._onStateChangeCallbacks = new Set();
23
-
24
- this.status = 'idle';
41
+ this[kPluginManagerInstances] = new Map();
25
42
  }
26
43
 
27
- /**
28
- * Register a plugin into soundworks.
29
- *
30
- * _A plugin must always be registered both on client-side and on server-side_
31
- *
32
- * Refer to the plugin documentation to check its options and proper way of
33
- * registering it.
34
- *
35
- * @param {string} id - Unique id of the plugin. Enables the registration of the
36
- * same plugin factory under different ids.
37
- * @param {Function} factory - Factory function that returns the Plugin class.
38
- * @param {object} [options={}] - Options to configure the plugin.
39
- * @param {array} [deps=[]] - List of plugins' names the plugin depends on, i.e.
40
- * the plugin initialization will start only after the plugins it depends on are
41
- * fully started themselves.
42
- * @see {@link client.PluginManager#register}
43
- * @see {@link server.PluginManager#register}
44
- * @example
45
- * // client-side
46
- * client.pluginManager.register('user-defined-id', pluginFactory);
47
- * // server-side
48
- * server.pluginManager.register('user-defined-id', pluginFactory);
49
- */
50
- register(id, ctor, options = {}, deps = []) {
51
- // For now we don't allow to register a plugin after `client|server.init()`.
52
- // This is subject to change in the future as we may want to dynamically
53
- // register new plugins during application lifetime.
54
- if (this._node.status === 'inited') {
55
- throw new Error(`[soundworks.PluginManager] Cannot register plugin (${id}) after "client.init()"`);
56
- }
57
-
58
- if (!isString(id)) {
59
- throw new Error(`[soundworks.PluginManager] Invalid argument, "pluginManager.register" first argument should be a string`);
60
- }
61
-
62
- if (!isPlainObject(options)) {
63
- throw new Error(`[soundworks.PluginManager] Invalid argument, "pluginManager.register" third optionnal argument should be an object`);
64
- }
65
-
66
- if (!Array.isArray(deps)) {
67
- throw new Error(`[soundworks.PluginManager] Invalid argument, "pluginManager.register" fourth optionnal argument should be an array`);
68
- }
44
+ #propagateStateChange(instance = null, status = null) {
45
+ if (instance !== null) {
46
+ // status is null if we forward some inner state change from the instance
47
+ if (status !== null) {
48
+ instance[kBasePluginStatus] = status;
49
+ }
69
50
 
70
- if (this._instances.has(id)) {
71
- throw new Error(`[soundworks:PluginManager] Plugin "${id}" already registered`);
51
+ const fullState = Object.fromEntries(this[kPluginManagerInstances]);
52
+ this.#onStateChangeCallbacks.forEach(callback => callback(fullState, instance));
53
+ } else {
54
+ const fullState = Object.fromEntries(this[kPluginManagerInstances]);
55
+ this.#onStateChangeCallbacks.forEach(callback => callback(fullState, null));
72
56
  }
73
-
74
- // we instanciate the plugin here, so that a plugin can register another one
75
- // in its own constructor.
76
- //
77
- // the dependencies must be created first, so that the instance can call
78
- // addDependency in its constructor
79
- this._dependencies.set(id, deps);
80
-
81
- const instance = new ctor(this._node, id, options);
82
- this._instances.set(id, instance);
83
57
  }
84
58
 
85
59
  /**
86
- * Manually add a dependency to a given plugin. Usefull to require a plugin
87
- * within a plugin
60
+ * Initialize all registered plugins.
61
+ *
62
+ * Executed during the {@link Client#init} or {@link Client#stop} initialization step.
88
63
  *
89
- */
90
- addDependency(pluginId, dependencyId) {
91
- const deps = this._dependencies.get(pluginId);
92
- deps.push(dependencyId);
93
- }
94
-
95
- /**
96
- * Returns the list of the registered plugins ids
97
- * @returns {string[]}
98
- */
99
- getRegisteredPlugins() {
100
- return Array.from(this._instances.keys());
101
- }
102
-
103
- /**
104
- * Initialize all the registered plugin. Executed during the `Client.init()` or
105
- * `Server.init()` initialization step.
106
64
  * @private
107
65
  */
108
- async start() {
66
+ async [kPluginManagerStart]() {
109
67
  logger.title('starting registered plugins');
110
68
 
111
- if (this.status !== 'idle') {
112
- throw new Error(`[soundworks:PluginManager] Cannot call "pluginManager.init()" twice`);
69
+ if (this.#status !== 'idle') {
70
+ throw new DOMException(`Cannot execute 'kPluginManagerStart' on BasePluginManager: Lifecycle methods must be called in following order: kPluginManagerStart, kPluginManagerStop`, 'InvalidAccessError');
113
71
  }
114
72
 
115
- this.status = 'inited';
116
- // instanciate all plugins
117
- for (let [id, instance] of this._instances.entries()) {
118
- instance.onStateChange(_values => this._propagateStateChange(instance));
73
+ this.#status = 'inited';
74
+ // instantiate all plugins
75
+ for (let instance of this[kPluginManagerInstances].values()) {
76
+ instance.onStateChange(() => this.#propagateStateChange(instance, null));
119
77
  }
120
78
 
121
- // propagate all 'idle' statuses before start
122
- this._propagateStateChange();
79
+ // propagate all 'idle' status before start
80
+ this.#propagateStateChange(null, null);
123
81
 
124
- const promises = Array.from(this._instances.keys()).map(id => this.unsafeGet(id));
82
+ const promises = Array.from(this[kPluginManagerInstances].keys()).map(id => this.getUnsafe(id));
125
83
 
126
84
  try {
127
85
  await Promise.all(promises);
128
- this.status = 'started';
86
+ this.#status = 'started';
129
87
  } catch (err) {
130
- this.status = 'errored';
88
+ this.#status = 'errored';
131
89
  throw err; // throw initial error
132
90
  }
133
91
  }
134
92
 
135
93
  /** @private */
136
- async stop() {
137
- for (let instance of this._instances.values()) {
94
+ async [kPluginManagerStop]() {
95
+ if (this.#status !== 'started') {
96
+ throw new DOMException(`Cannot execute 'kPluginManagerStop' on BasePluginManager: Lifecycle methods must be called in following order: kPluginManagerStart, kPluginManagerStop`, 'InvalidAccessError');
97
+ }
98
+
99
+ for (let instance of this[kPluginManagerInstances].values()) {
138
100
  await instance.stop();
139
101
  }
140
102
  }
141
103
 
142
104
  /**
143
- * Retrieve an fully started instance of a registered plugin, without checking
144
- * that the pluginManager has started. This is required for starting the plugin
145
- * manager itself and to require a plugin from within another plugin
105
+ * Status of the plugin manager
146
106
  *
107
+ * @type {'idle'|'inited'|'started'|'errored'}
108
+ */
109
+ get status() {
110
+ return this.#status;
111
+ }
112
+
113
+ /**
114
+ * Alias for existing plugins (i.e. plugin-scripting), remove once updated
147
115
  * @private
116
+ * @deprecated
148
117
  */
149
118
  async unsafeGet(id) {
119
+ return this.getUnsafe(id);
120
+ }
121
+
122
+ /**
123
+ * Retrieve an fully started instance of a registered plugin without checking
124
+ * that the pluginManager is started.
125
+ *
126
+ * This method is required for starting the plugin manager itself and to require
127
+ * a plugin from within another plugin.
128
+ *
129
+ * _Warning: Unless you are developing your own plugins, you should not have to use
130
+ * this method_
131
+ */
132
+ async getUnsafe(id) {
150
133
  if (!isString(id)) {
151
- throw new Error(`[soundworks.PluginManager] Invalid argument, "pluginManager.get(name)" argument should be a string`);
134
+ throw new TypeError(`Cannot execute 'get' on BasePluginManager: Argument 1 must be of type string`);
152
135
  }
153
136
 
154
- if (!this._instances.has(id)) {
155
- throw new Error(`[soundworks:PluginManager] Cannot get plugin "${id}", plugin is not registered`);
137
+ if (!this[kPluginManagerInstances].has(id)) {
138
+ throw new ReferenceError(`Cannot execute 'get' on BasePluginManager: Plugin '${id}' is not registered`);
156
139
  }
157
140
 
158
141
  // @note - For now, all instances are created at the beginning of `start()`
159
142
  // to be able to properly propagate the states. The code bellow should allow
160
143
  // to dynamically register and launch plugins at runtime.
161
144
  //
162
- // if (!this._instances.has(id)) {
163
- // const { ctor, options } = this._dependencies.get(id);
164
- // const instance = new ctor(this._node, id, options);
165
- // this._instances.set(id, instance);
145
+ // if (!this[kPluginManagerInstances].has(id)) {
146
+ // const { ctor, options } = this.#dependencies.get(id);
147
+ // const instance = new ctor(this.#node, id, options);
148
+ // this[kPluginManagerInstances].set(id, instance);
166
149
  // }
167
150
 
168
- const instance = this._instances.get(id);
151
+ const instance = this[kPluginManagerInstances].get(id);
169
152
 
170
153
  // recursively get the dependency chain
171
- const deps = this._dependencies.get(id);
172
- const promises = deps.map(id => this.unsafeGet(id));
154
+ const deps = this.#dependencies.get(id);
155
+ const promises = deps.map(id => this.getUnsafe(id));
173
156
 
174
157
  await Promise.all(promises);
175
158
 
176
159
  // 'plugin.start' has already been called, just await the start promise
177
- if (this._instanceStartPromises.has(id)) {
178
- await this._instanceStartPromises.get(id);
160
+ if (this.#instanceStartPromises.has(id)) {
161
+ await this.#instanceStartPromises.get(id);
179
162
  } else {
180
- this._propagateStateChange(instance, 'inited');
163
+ this.#propagateStateChange(instance, 'inited');
181
164
  let errored = false;
182
165
 
183
166
  try {
184
167
  const startPromise = instance.start();
185
- this._instanceStartPromises.set(id, startPromise);
168
+ this.#instanceStartPromises.set(id, startPromise);
186
169
 
187
170
  await startPromise;
188
171
  } catch (err) {
189
172
  errored = true;
190
- this._propagateStateChange(instance, 'errored');
173
+ this.#propagateStateChange(instance, 'errored');
191
174
  throw err;
192
175
  }
193
176
 
194
177
  // this looks silly but it prevents the try / catch to catch errors that could
195
178
  // be triggered by the propagate status callback, putting the plugin in errored state
196
179
  if (!errored) {
197
- this._propagateStateChange(instance, 'started');
180
+ this.#propagateStateChange(instance, 'started');
198
181
  }
199
182
  }
200
183
 
201
184
  return instance;
202
185
  }
203
186
 
187
+ /**
188
+ * Register a plugin into the manager.
189
+ *
190
+ * _A plugin must always be registered both on client-side and on server-side_
191
+ *
192
+ * Plugins must be registered between the instantiation of {@link Client} and {@link Server},
193
+ * and their respective initialization, i.e.:
194
+ *
195
+ * ```js
196
+ * const client = new Client(config);
197
+ * client.pluginManager.register('my-plugin', plugin);
198
+ * await client.start();
199
+ * ```
200
+ *
201
+ * Refer to the plugins documentation to check their configuration options and API.
202
+ *
203
+ * @param {string} id - Unique id of the plugin. Enables the registration of the
204
+ * same plugin factory under different ids.
205
+ * @param {Function} ctor - The class returned by the plugin factory method.
206
+ * @param {object} [options={}] - Options to configure the plugin.
207
+ * @param {array} [deps=[]] - List of plugins' names the plugin depends on, i.e.
208
+ * the plugin initialization will begin only after the plugins it depends on are
209
+ * fully started themselves.
210
+ * @see {@link ClientPluginManager#register}
211
+ * @see {@link ServerPluginManager#register}
212
+ * @example
213
+ * // client-side
214
+ * client.pluginManager.register('user-defined-id', pluginFactory);
215
+ * // server-side
216
+ * server.pluginManager.register('user-defined-id', pluginFactory);
217
+ */
218
+ register(id, ctor, options = {}, deps = []) {
219
+ // For now we don't allow to register a plugin after `client|server.init()`.
220
+ // This is subject to change in the future as we may want to dynamically
221
+ // register new plugins during application lifetime.
222
+ if (this.#node.status === 'inited') {
223
+ throw new DOMException(`Cannot execute 'register' on BasePluginManager: Host (client or server) has already been initialized`, 'InvalidAccessError');
224
+ }
225
+
226
+ if (!isString(id)) {
227
+ throw new TypeError(`Cannot execute 'register' on BasePluginManager: Argument 1 must be a string`);
228
+ }
229
+
230
+ if (!isPlainObject(options)) {
231
+ throw new TypeError(`Cannot execute 'register' on BasePluginManager: Argument 3 must be an object`);
232
+ }
233
+
234
+ if (!Array.isArray(deps)) {
235
+ throw new TypeError(`Cannot execute 'register' on BasePluginManager: Argument 3 must be an array`);
236
+ }
237
+
238
+ if (this[kPluginManagerInstances].has(id)) {
239
+ throw new DOMException(`Cannot execute 'register' on BasePluginManager: A plugin with same id (${id}) has already registered`, 'NotSupportedError');
240
+ }
241
+
242
+ // We instantiate the plugin here, so that a plugin can register another one
243
+ // in its own constructor.
244
+ //
245
+ // The dependencies must be created first, so that the instance can call
246
+ // addDependency in its constructor
247
+ this.#dependencies.set(id, deps);
248
+
249
+ const instance = new ctor(this.#node, id, options);
250
+ this[kPluginManagerInstances].set(id, instance);
251
+ }
252
+
253
+ /**
254
+ * Manually add a dependency to a given plugin.
255
+ *
256
+ * Useful to require a plugin within a plugin
257
+ */
258
+ addDependency(pluginId, dependencyId) {
259
+ const deps = this.#dependencies.get(pluginId);
260
+ deps.push(dependencyId);
261
+ }
262
+
263
+ /**
264
+ * Returns the list of the registered plugins ids
265
+ * @returns {string[]}
266
+ */
267
+ getRegisteredPlugins() {
268
+ return Array.from(this[kPluginManagerInstances].keys());
269
+ }
270
+
204
271
  /**
205
272
  * Propagate a notification each time a plugin is updated (status or inner state).
206
273
  * The callback will receive the list of all plugins as first parameter, and the
@@ -208,10 +275,8 @@ class BasePluginManager {
208
275
  *
209
276
  * _In most cases, you should not have to rely on this method._
210
277
  *
211
- * @param {client.PluginManager~onStateChangeCallback|server.PluginManager~onStateChangeCallback} callback
212
- * Callback to be executed on state change
213
- * @param {client.PluginManager~deleteOnStateChangeCallback|client.PluginManager~deleteOnStateChangeCallback}
214
- * Function to execute to listening for changes.
278
+ * @param {pluginManagerOnStateChangeCallback} callback - Callback to execute on state change
279
+ * @returns {pluginManagerDeleteOnStateChangeCallback} - Clear the subscription when executed
215
280
  * @example
216
281
  * const unsubscribe = client.pluginManager.onStateChange(pluginList, initiator => {
217
282
  * // log the current status of all plugins
@@ -227,24 +292,8 @@ class BasePluginManager {
227
292
  * unsubscribe();
228
293
  */
229
294
  onStateChange(callback) {
230
- this._onStateChangeCallbacks.add(callback);
231
- return () => this._onStateChangeCallbacks.delete(callback);
232
- }
233
-
234
- /** @private */
235
- _propagateStateChange(instance = null, status = null) {
236
- if (instance !== null) {
237
- // status is null if wew forward some inner state change from the instance
238
- if (status !== null) {
239
- instance.status = status;
240
- }
241
-
242
- const fullState = Object.fromEntries(this._instances);
243
- this._onStateChangeCallbacks.forEach(callback => callback(fullState, instance));
244
- } else {
245
- const fullState = Object.fromEntries(this._instances);
246
- this._onStateChangeCallbacks.forEach(callback => callback(fullState, null));
247
- }
295
+ this.#onStateChangeCallbacks.add(callback);
296
+ return () => this.#onStateChangeCallbacks.delete(callback);
248
297
  }
249
298
  }
250
299