@soundworks/core 4.0.0-alpha.1 → 4.0.0-alpha.2

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.
@@ -1,195 +1,6 @@
1
1
  import cloneDeep from 'lodash.clonedeep';
2
2
  import equal from 'fast-deep-equal';
3
3
 
4
- /**
5
- * @typedef {Object} server.SharedStateManagerServer~schema
6
- *
7
- * Description of a schema to be register by the {@link server.ServerStateManagerServer}
8
- * A schema consists of a combinaison of key value pairs where the key is the
9
- * name of the parameter, and the value is an object describing the parameter.
10
- *
11
- * Available types are:
12
- * - {@link server.SharedStateManagerServer~schemaBooleanDef}
13
- * - {@link server.SharedStateManagerServer~schemaStringDef}
14
- * - {@link server.SharedStateManagerServer~schemaIntegerDef}
15
- * - {@link server.SharedStateManagerServer~schemaFloatDef}
16
- * - {@link server.SharedStateManagerServer~schemaEnumDef}
17
- * - {@link server.SharedStateManagerServer~schemaAnyDef}
18
- *
19
- * @example
20
- * {
21
- * myBoolean: {
22
- * type: 'boolean'
23
- * default: false,
24
- * },
25
- * myFloat: {
26
- * type: 'float'
27
- * default: 0.1,
28
- * min: -1,
29
- * max: 1,
30
- * event: true,
31
- * }
32
- * }
33
- */
34
- /**
35
- * @typedef {Object} server.SharedStateManagerServer~schemaBooleanDef
36
- *
37
- * @property {String} type='boolean' - Define a boolean parameter.
38
- * @property {Boolean} default - Default value of the parameter.
39
- * @property {Boolean} [nullable=false] - Define if the parameter is nullable. If
40
- * set to `true` the parameter `default` is set to `null`.
41
- * @property {Boolean} [event=false] - Define if the parameter is a volatile, e.g.
42
- * set its value back to `null` after propagation. When `true`, `nullable` is
43
- * automatically set to `true` and `default` to `null`.
44
- * @property {Boolean} [filterChange=true] - Setting this option to `false` forces
45
- * the propagation of a parameter even when its value do not change. It
46
- * offers a kind of middle ground between the default bahavior (e.g. where
47
- * only changed values are propagated) and the behavior of the `event` option
48
- * (which has no state per se). As such, setting this options to `false` if
49
- * `event=true` does not make sens.
50
- * @property {Boolean} [immediate=false] - Setting this option to `true` will
51
- * trigger any change (e.g. call the `onUpdate` listeners) immediately on the
52
- * state that generate the update (i.e. calling `set`), before propagating the
53
- * change on the network. This option can be usefull in cases the network
54
- * would introduce a noticeable latency on the client. If for some reason
55
- * the value is overriden server-side (e.g. in an `updateHook`) the listeners
56
- * will be called again on when the "real" / final value will be received.
57
- * @property {Object} [metas={}] - Optionnal metadata of the parameter.
58
- */
59
- /**
60
- * @typedef {Object} server.SharedStateManagerServer~schemaStringDef
61
- *
62
- * @property {String} type='string' - Define a boolean parameter.
63
- * @property {Mixed} default - Default value of the parameter.
64
- * @property {Boolean} [nullable=false] - Define if the parameter is nullable. If
65
- * set to `true` the parameter `default` is set to `null`.
66
- * @property {Boolean} [event=false] - Define if the parameter is a volatile, e.g.
67
- * set its value back to `null` after propagation. When `true`, `nullable` is
68
- * automatically set to `true` and `default` to `null`.
69
- * @property {Boolean} [filterChange=true] - Setting this option to `false` forces
70
- * the propagation of a parameter even when its value do not change. It
71
- * offers a kind of middle ground between the default bahavior (e.g. where
72
- * only changed values are propagated) and the behavior of the `event` option
73
- * (which has no state per se). As such, setting this options to `false` if
74
- * `event=true` does not make sens.
75
- * @property {Boolean} [immediate=false] - Setting this option to `true` will
76
- * trigger any change (e.g. call the `onUpdate` listeners) immediately on the
77
- * state that generate the update (i.e. calling `set`), before propagating the
78
- * change on the network. This option can be usefull in cases the network
79
- * would introduce a noticeable latency on the client. If for some reason
80
- * the value is overriden server-side (e.g. in an `updateHook`) the listeners
81
- * will be called again on when the "real" / final value will be received.
82
- * @property {Object} [metas={}] - Optionnal metadata of the parameter.
83
- */
84
- /**
85
- @typedef {Object} server.SharedStateManagerServer~schemaIntegerDef
86
- *
87
- * @property {String} type='integer' - Define a boolean parameter.
88
- * @property {Mixed} default - Default value of the parameter.
89
- * @property {Number} [min=-Infinity] - Minimum value of the parameter.
90
- * @property {Number} [max=+Infinity] - Maximum value of the parameter.
91
- * @property {Boolean} [nullable=false] - Define if the parameter is nullable. If
92
- * set to `true` the parameter `default` is set to `null`.
93
- * @property {Boolean} [event=false] - Define if the parameter is a volatile, e.g.
94
- * set its value back to `null` after propagation. When `true`, `nullable` is
95
- * automatically set to `true` and `default` to `null`.
96
- * @property {Boolean} [filterChange=true] - Setting this option to `false` forces
97
- * the propagation of a parameter even when its value do not change. It
98
- * offers a kind of middle ground between the default bahavior (e.g. where
99
- * only changed values are propagated) and the behavior of the `event` option
100
- * (which has no state per se). As such, setting this options to `false` if
101
- * `event=true` does not make sens.
102
- * @property {Boolean} [immediate=false] - Setting this option to `true` will
103
- * trigger any change (e.g. call the `onUpdate` listeners) immediately on the
104
- * state that generate the update (i.e. calling `set`), before propagating the
105
- * change on the network. This option can be usefull in cases the network
106
- * would introduce a noticeable latency on the client. If for some reason
107
- * the value is overriden server-side (e.g. in an `updateHook`) the listeners
108
- * will be called again on when the "real" / final value will be received.
109
- * @property {Object} [metas={}] - Optionnal metadata of the parameter.
110
- */
111
- /**
112
- * @typedef {Object} server.SharedStateManagerServer~schemaFloatDef
113
- *
114
- * @property {String} [type='float'] - Float parameter.
115
- * @property {Mixed} default - Default value.
116
- * @property {Number} [min=-Infinity] - Minimum value.
117
- * @property {Number} [max=+Infinity] - Maximum value.
118
- * @property {Boolean} [nullable=false] - Define if the parameter is nullable. If
119
- * set to `true` the parameter `default` is set to `null`.
120
- * @property {Boolean} [event=false] - Define if the parameter is a volatile, e.g.
121
- * set its value back to `null` after propagation. When `true`, `nullable` is
122
- * automatically set to `true` and `default` to `null`.
123
- * @property {Boolean} [filterChange=true] - Setting this option to `false` forces
124
- * the propagation of a parameter even when its value do not change. It
125
- * offers a kind of middle ground between the default bahavior (e.g. where
126
- * only changed values are propagated) and the behavior of the `event` option
127
- * (which has no state per se). As such, setting this options to `false` if
128
- * `event=true` does not make sens.
129
- * @property {Boolean} [immediate=false] - Setting this option to `true` will
130
- * trigger any change (e.g. call the `onUpdate` listeners) immediately on the
131
- * state that generate the update (i.e. calling `set`), before propagating the
132
- * change on the network. This option can be usefull in cases the network
133
- * would introduce a noticeable latency on the client. If for some reason
134
- * the value is overriden server-side (e.g. in an `updateHook`) the listeners
135
- * will be called again on when the "real" / final value will be received.
136
- * @property {Object} [metas={}] - Optionnal metadata of the parameter.
137
- */
138
- /**
139
- * @typedef {Object} server.SharedStateManagerServer~schemaEnumDef
140
- *
141
- * @property {String} [type='enum'] - Enum parameter.
142
- * @property {Mixed} default - Default value of the parameter.
143
- * @property {Array} list - Possible values of the parameter.
144
- * @property {Boolean} [nullable=false] - Define if the parameter is nullable. If
145
- * set to `true` the parameter `default` is set to `null`.
146
- * @property {Boolean} [event=false] - Define if the parameter is a volatile, e.g.
147
- * set its value back to `null` after propagation. When `true`, `nullable` is
148
- * automatically set to `true` and `default` to `null`.
149
- * @property {Boolean} [filterChange=true] - Setting this option to `false` forces
150
- * the propagation of a parameter even when its value do not change. It
151
- * offers a kind of middle ground between the default bahavior (e.g. where
152
- * only changed values are propagated) and the behavior of the `event` option
153
- * (which has no state per se). As such, setting this options to `false` if
154
- * `event=true` does not make sens.
155
- * @property {Boolean} [immediate=false] - Setting this option to `true` will
156
- * trigger any change (e.g. call the `onUpdate` listeners) immediately on the
157
- * state that generate the update (i.e. calling `set`), before propagating the
158
- * change on the network. This option can be usefull in cases the network
159
- * would introduce a noticeable latency on the client. If for some reason
160
- * the value is overriden server-side (e.g. in an `updateHook`) the listeners
161
- * will be called again on when the "real" / final value will be received.
162
- * @property {Object} [metas={}] - Optionnal metadata of the parameter.
163
- */
164
- /**
165
- * @typedef {Object} server.SharedStateManagerServer~schemaAnyDef
166
- *
167
- * Note that the `any` type always return a shallow copy of the state internal
168
- * value. Mutating the returned value will not modify the internal state.
169
- *
170
- * @property {String} [type='any'] - Parameter of any type.
171
- * @property {Mixed} default - Default value of the parameter.
172
- * @property {Boolean} [nullable=false] - Define if the parameter is nullable. If
173
- * set to `true` the parameter `default` is set to `null`.
174
- * @property {Boolean} [event=false] - Define if the parameter is a volatile, e.g.
175
- * set its value back to `null` after propagation. When `true`, `nullable` is
176
- * automatically set to `true` and `default` to `null`.
177
- * @property {Boolean} [filterChange=true] - Setting this option to `false` forces
178
- * the propagation of a parameter even when its value do not change. It
179
- * offers a kind of middle ground between the default bahavior (e.g. where
180
- * only changed values are propagated) and the behavior of the `event` option
181
- * (which has no state per se). As such, setting this options to `false` if
182
- * `event=true` does not make sens.
183
- * @property {Boolean} [immediate=false] - Setting this option to `true` will
184
- * trigger any change (e.g. call the `onUpdate` listeners) immediately on the
185
- * state that generate the update (i.e. calling `set`), before propagating the
186
- * change on the network. This option can be usefull in cases the network
187
- * would introduce a noticeable latency on the client. If for some reason
188
- * the value is overriden server-side (e.g. in an `updateHook`) the listeners
189
- * will be called again on when the "real" / final value will be received.
190
- * @property {Object} [metas={}] - Optionnal metadata of the parameter.
191
- */
192
-
193
4
  export const sharedOptions = {
194
5
  nullable: false,
195
6
  event: false, // if event=true, nullable=true
@@ -422,7 +233,7 @@ class ParameterBag {
422
233
  /**
423
234
  * Define if the parameter exists.
424
235
  *
425
- * @param {String} name - Name of the parameter.
236
+ * @param {string} name - Name of the parameter.
426
237
  * @return {Boolean}
427
238
  */
428
239
  has(name) {
@@ -432,7 +243,7 @@ class ParameterBag {
432
243
  /**
433
244
  * Return values of all parameters as a flat object.
434
245
  *
435
- * @return {Object}
246
+ * @return {object}
436
247
  */
437
248
  getValues() {
438
249
  let values = {};
@@ -448,7 +259,7 @@ class ParameterBag {
448
259
  * Return the value of the given parameter. If the parameter is of `any` type,
449
260
  * a deep copy is returned.
450
261
  *
451
- * @param {String} name - Name of the parameter.
262
+ * @param {string} name - Name of the parameter.
452
263
  * @return {Mixed} - Value of the parameter.
453
264
  */
454
265
  get(name) {
@@ -468,9 +279,9 @@ class ParameterBag {
468
279
  * (aka if previous value is different from new value) all registered
469
280
  * callbacks are registered.
470
281
  *
471
- * @param {String} name - Name of the parameter.
282
+ * @param {string} name - Name of the parameter.
472
283
  * @param {Mixed} value - Value of the parameter.
473
- * @param {Boolean} [forcePropagation=false] - if true, propagate value even
284
+ * @param {boolean} [forcePropagation=false] - if true, propagate value even
474
285
  * if the value has not changed.
475
286
  * @return {Array} - [new value, updated flag].
476
287
  */
@@ -504,7 +315,7 @@ class ParameterBag {
504
315
  * @note - prefer `state.set(state.getInitValues())`
505
316
  * or `state.set(state.getDefaultValues())`
506
317
  *
507
- * @param {String} [name=null] - Name of the parameter to reset.
318
+ * @param {string} [name=null] - Name of the parameter to reset.
508
319
  */
509
320
  // reset(name = null) {
510
321
  // if (name !== null) {
@@ -519,7 +330,7 @@ class ParameterBag {
519
330
  /**
520
331
  * Return the given schema along with the initialization values.
521
332
  *
522
- * @return {Object}
333
+ * @return {object}
523
334
  */
524
335
  getSchema(name = null) {
525
336
  if (name === null) {
@@ -2,44 +2,116 @@ import Client from './Client.js';
2
2
  import Server from './Server.js';
3
3
 
4
4
  /**
5
- * Base class to extend in order to create the server-side counterpart of
6
- * a {@link client.Context}. If not defined, a default context will be created
5
+ * Base class to extend in order to implment the optionnal server-side counterpart
6
+ * of a {@link client.Context}. If not defined, a default context will be created
7
7
  * and used by the server.
8
8
  *
9
+ * In the `soundworks` paradigm, a client has a "role" (e.g. _player_, _controller_)
10
+ * see {@link client.Client#role}) and can be in different "contexts" (e.g. different
11
+ * part of the experience such as sections of a music piece, etc.). The
12
+ * {@link client.Context} and optionnal {@link serverContext} abstractions provide
13
+ * a simple and unified way to model these reccuring aspects of an application.
14
+ *
15
+ * If a `server.Context` is recognized as the server-side counterpart of a
16
+ * {@link client.Context}, based on their respective `name` (see {@link client.Context#name}
17
+ * and {@link server.Context#name}), `soundworks` will ensure the logic defined
18
+ * by the server-side Context will be executed at the beginning of the
19
+ * {@link client.Client#enter} and {@link client.Client#exit} methods. The example
20
+ * show how soundwords handles (and guarantees) the order of the `enter()` steps
21
+ * between the client-side and the server-side parts of the context. The same goes
22
+ * for the `exit()` method.
23
+ *
24
+ * ```
25
+ * // client-side
26
+ * import { Context } from '@soundworks/core/client.js';
27
+ *
28
+ * class MyContext extends Context {
29
+ * async enter() {
30
+ * // 1. client side context enter() starts
31
+ * // server-side logic is triggered first
32
+ * await super.enter();
33
+ * // 4. server-side context enter() is fully done
34
+ * // some async job can be done here
35
+ * await new Promise(resolve => setTimeout(resolve, 1000));
36
+ * // 5. client-side context enter() ends
37
+ * }
38
+ * }
39
+ *
40
+ * // Instanciate the context (assuming the `client.role` is 'test')
41
+ * const myContext = new MyContext(client);
42
+ *
43
+ * // At some point in the application, the client enters the context trigerring
44
+ * // the steps 1 to 5 described in the client-side and server-side `enter()`
45
+ * // implementations. Note that the server-side `enter()` is never called manually.
46
+ * await myContext.enter();
47
+ * ```
48
+ *
49
+ * ```
50
+ * // server-side
51
+ * import { Context } from '@soundworks/core/server.js';
52
+ *
53
+ * class MyContext extends Context {
54
+ * async enter(client) {
55
+ * // 2. server-side context enter() starts
56
+ * await super.enter(client);
57
+ * // some async job can be done here
58
+ * await new Promise(resolve => setTimeout(resolve, 1000));
59
+ * // 3. server-side context enter() ends
60
+ * }
61
+ * }
62
+ *
63
+ * // Instantiate the context
64
+ * const myContext = new Context(server);
65
+ * ```
66
+ *
9
67
  * @memberof server
10
68
  */
11
69
  class Context {
70
+ /**
71
+ * @param {client.Client} client - The soundworks client instance.
72
+ * @param {string|string[]} [roles=[]] - Optionnal list of client roles that can
73
+ * use this context. In large applications, this may be usefull to guarantee
74
+ * that a context can be consumed only by specific client roles, throwing an
75
+ * error if any other client role tries to use it. If empty, no access policy
76
+ * will be used.
77
+ * @throws Will throw if the first argument is not a soundworks server instance.
78
+ */
12
79
  constructor(server, roles = []) {
13
80
  if (!(server instanceof Server)) {
14
81
  throw new Error(`[soundworks:Context] Invalid argument, context "${this.constructor.name}" should receive a "soundworks.Server" instance as first argument`);
15
82
  }
16
83
 
17
- if (roles === null) {
18
- throw new Error('Invalid client types');
19
- }
20
-
21
84
  /**
22
85
  * soundworks server
23
86
  * @type {server.Server}
87
+ * @readonly
24
88
  */
25
89
  this.server = server;
26
90
 
27
91
  /**
28
92
  * List of clients that are currently in this context
29
- * @type {Client[]}
93
+ * @type {server.Client[]}
30
94
  */
31
95
  this.clients = new Set();
32
96
 
33
97
  /**
34
98
  * Status of the context ('idle', 'inited', 'started' or 'errored')
35
- * @type {String}
99
+ * @type {string}
100
+ * @readonly
36
101
  */
37
102
  this.status = 'idle';
38
103
 
39
104
  /**
40
- * List of client role associated with this context.
105
+ * List of client roles that can use this context.
106
+ * @type {string[]}
107
+ * @readonly
41
108
  */
42
109
  roles = Array.isArray(roles) ? roles : [roles];
110
+
111
+ if (roles.length === 0) {
112
+ roles = Object.keys(server.config.app.clients);
113
+ }
114
+
43
115
  this.roles = new Set(roles);
44
116
 
45
117
  // register in context manager
@@ -47,32 +119,87 @@ class Context {
47
119
  }
48
120
 
49
121
  /**
50
- * Name of the context, default to the class name.
51
- * Override the `get name()` getter to use a user-defined context name.
122
+ * Optionnal user-defined name of the context (defaults to the class name).
123
+ *
124
+ * The context manager will match the client-side and server-side contexts based
125
+ * on this name. If the {@link server.ContextManager} don't find a corresponding
126
+ * user-defined context with the same name, it will use a default (noop) context.
127
+ *
128
+ * @readonly
129
+ * @type {string}
130
+ * @example
131
+ * // server-side and client-side contexts are matched based on their respective `name`
132
+ * class MyContext extends Context {
133
+ * get name() {
134
+ * return 'my-user-defined-context-name';
135
+ * }
136
+ * }
52
137
  */
53
138
  get name() {
54
139
  return this.constructor.name;
55
140
  }
56
141
 
57
142
  /**
58
- * Method automatically called when the server starts, or lazilly called if
59
- * the context is created after `server.start()`
143
+ * Start the context. This method is lazilly called when a client enters the
144
+ * context for the first time (cf. ${server.Context#enter}). If you know some
145
+ * some heavy and/or potentially long job has to be done when starting the context
146
+ * (e.g. connect to a database, parsing a long file) it may be a good practice
147
+ * to call it explicitely.
60
148
  *
61
- * _WARNING: this method should never be called manually._
149
+ * This method should be implemented to perform operations that are valid for the
150
+ * whole lifetime of the context, regardless a client enters or exits the context.
151
+ *
152
+ * @example
153
+ * import { Context } from '@soundworks/core/server.js';
154
+ *
155
+ * class MyContext extends Context {
156
+ * async start() {
157
+ * await super.start();
158
+ * await this.doSomeLongJob();
159
+ * }
160
+ * }
161
+ *
162
+ * // Instantiate the context
163
+ * const myContext = new Context(server, ['test']);
164
+ * // manually start the context to perform the long operation before the first
165
+ * // client enters the context
166
+ * await myContext.start();
167
+ * ```
62
168
  */
63
169
  async start() {}
64
170
 
65
171
  /**
66
- * Method automatically called when the server stops.
172
+ * Stop the context. The method that is automatically called when the server
173
+ * stops. It should be used to cleanup context wise operations made in `start()`
174
+ * (e.g. disconnect from a database, release a file handle).
67
175
  *
68
176
  * _WARNING: this method should never be called manually._
69
177
  */
70
178
  async stop() {}
71
179
 
72
180
  /**
73
- * Method automatically called when the client enters the context.
181
+ * Enter the context. Implement this method to define the logic that should be
182
+ * done (e.g. creating a shared state, etc.) when a client enters the context.
183
+ *
184
+ * If the context has not been started yet, the `start` method is implicitely executed.
74
185
  *
75
186
  * _WARNING: this method should never be called manually._
187
+ *
188
+ * @param {server.Client} client - Server-side representation of the client
189
+ * that enters the context.
190
+ * @returns {Promise} - Promise that resolves when the context is entered.
191
+ * @example
192
+ * class MyContext extends Context {
193
+ * async enter(client) {
194
+ * await super.enter(client);
195
+ * registerTheClientSomewhere(client);
196
+ * }
197
+ *
198
+ * async exit(client) {
199
+ * await super.exit(client);
200
+ * unregisterTheClientSomewhere(client);
201
+ * }
202
+ * }
76
203
  */
77
204
  async enter(client) {
78
205
  if (!(client instanceof Client)) {
@@ -83,9 +210,26 @@ class Context {
83
210
  }
84
211
 
85
212
  /**
86
- * Method automatically called when the client exits the context.
213
+ * Exit the context. Implement this method to define the logic that should be
214
+ * done (e.g. delete a shared state, etc.) when a client exits the context.
87
215
  *
88
- * _WARNING: this method should never be called manually._
216
+ * * _WARNING: this method should never be called manually._
217
+ *
218
+ * @param {server.Client} client - Server-side representation of the client
219
+ * that exits the context.
220
+ * @returns {Promise} - Promise that resolves when the context is exited.
221
+ * @example
222
+ * class MyContext extends Context {
223
+ * async enter(client) {
224
+ * await super.enter(client);
225
+ * this.state = await this.client.stateManager.create('my-context-state');
226
+ * }
227
+ *
228
+ * async exit(client) {
229
+ * await super.exit(client);
230
+ * await this.state.delete();
231
+ * }
232
+ * }
89
233
  */
90
234
  async exit(client) {
91
235
  if (!(client instanceof Client)) {
@@ -57,6 +57,7 @@ class ContextCollection {
57
57
  * _WARNING: Most of the time, you should not have to manipulate the context manager directly._
58
58
  *
59
59
  * @memberof server
60
+ * @hideconstructor
60
61
  */
61
62
  class ContextManager {
62
63
  /**
@@ -91,10 +92,9 @@ class ContextManager {
91
92
  /**
92
93
  * Retrieve a started context from its name.
93
94
  *
94
- * @see {server.Context#name}
95
- * @param {String} contextName - Name of the context.
95
+ * _WARNING: Most of the time, you should not have to call this method manually._
96
96
  *
97
- * @private
97
+ * @param {server.Context#name} contextName - Name of the context.
98
98
  */
99
99
  async get(contextName) {
100
100
  if (!this._contexts.has(contextName)) {
@@ -136,9 +136,8 @@ class ContextManager {
136
136
  if (!this._contexts.has(contextName)) {
137
137
  // create default context for all client types
138
138
  const ctor = createNamedContextClass(contextName);
139
- const roles = Object.keys(this.server.config.app.clients);
140
139
  // this will automatically register the context in the context manager
141
- new ctor(this.server, roles);
140
+ new ctor(this.server);
142
141
  }
143
142
 
144
143
  // we ensure context is started, even lazilly after server.start()
@@ -14,7 +14,8 @@ import BasePlugin from '../common/BasePlugin.js';
14
14
  */
15
15
 
16
16
  /**
17
- * Base class to extend in order to create new `soundworks` plugins.
17
+ * Base class to extend in order to create the server-side counterpart of a
18
+ * `soundworks` plugin.
18
19
  *
19
20
  * In the `soundworks` paradigm, a plugin is a component that allows to extend
20
21
  * the framework capabilities by encapsulating common and reusable logic in
@@ -23,7 +23,7 @@ import Server from './Server.js';
23
23
  *
24
24
  * Plugins should always be registered both client-side and server-side,
25
25
  * and before {@link client.Client#start} or {@link server.Server#start}
26
- * are called for proper initialization.
26
+ * to be properly initialized.
27
27
  *
28
28
  * In some sitautions, you might want to register the same plugin factory several times
29
29
  * using different ids (e.g. for watching several parts of the file system, etc.).
@@ -33,12 +33,32 @@ import Server from './Server.js';
33
33
  * for more informations on the available plugins.
34
34
  *
35
35
  * ```
36
+ * // client-side
37
+ * import { Client } from '@soundworks/core/client.js';
38
+ * import syncPlugin from '@soundworks/plugin-sync/client.js';
39
+ *
40
+ * const client = new Client(config);
41
+ * // register the plugin before `client.start()`
42
+ * client.pluginManager.register('sync', syncPlugin);
43
+ *
44
+ * await client.start();
45
+ *
46
+ * const sync = await client.pluginManager.get('sync');
47
+ *
48
+ * setInterval(() => {
49
+ * // log the estimated global synced clock alongside the local clock.
50
+ * console.log(sync.getSyncTime(), sync.getLocalTime());
51
+ * }, 1000);
52
+ * ```
53
+ *
54
+ * ```
55
+ * // server-side
36
56
  * import { Server } from '@soundworks/core/server.js';
37
- * import platformPlugin from '@soundworks/plugin-sync/server.js';
57
+ * import syncPlugin from '@soundworks/plugin-sync/server.js';
38
58
  *
39
59
  * const server = new Server(config);
40
60
  * // register the plugin before `server.start()`
41
- * server.pluginManager.register('sync', pluginSync);
61
+ * server.pluginManager.register('sync', syncPlugin);
42
62
  *
43
63
  * await server.start();
44
64
  *
@@ -86,8 +106,8 @@ class PluginManager extends BasePluginManager {
86
106
  * initialization (e.g. to display initialization screen, etc.), you should rely
87
107
  * on the `onStateChange` method.
88
108
  *
89
- * _Note: the async API is designed to enable the dynamic creation of plugins (hopefully
90
- * without brealing changes) in a future release._
109
+ * _Note: the async API is designed to enable the dynamic creation of plugins
110
+ * (hopefully without brealing changes) in a future release._
91
111
  *
92
112
  * @param {server.Plugin#id} id - Id of the plugin as defined when registered.
93
113
  * @returns {server.Plugin}
@@ -100,7 +120,7 @@ class PluginManager extends BasePluginManager {
100
120
  throw new Error(`[soundworks.PluginManager] Cannot get plugin before "server.init()"`);
101
121
  }
102
122
 
103
- return super.getUnsafe(id);
123
+ return super.unsafeGet(id);
104
124
  }
105
125
 
106
126
  // server only methods