@soundworks/core 4.0.0-alpha.21 → 4.0.0-alpha.23

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 (87) hide show
  1. package/CHANGELOG.md +14 -3
  2. package/package.json +15 -15
  3. package/src/client/Client.js +233 -188
  4. package/src/client/Socket.js +84 -247
  5. package/src/client/index.js +6 -0
  6. package/src/common/constants.js +0 -1
  7. package/src/common/logger.js +15 -0
  8. package/src/common/sockets-utils.js +0 -63
  9. package/src/common/version.js +2 -0
  10. package/src/server/Plugin.js +22 -10
  11. package/src/server/Server.js +37 -36
  12. package/src/server/Socket.js +126 -250
  13. package/src/server/Sockets.js +103 -127
  14. package/src/server/audit-network-latency.worker.js +4 -3
  15. package/src/server/index.js +6 -0
  16. package/types/client/Client.d.ts +41 -8
  17. package/types/client/Client.d.ts.map +1 -1
  18. package/types/client/Context.d.ts +40 -14
  19. package/types/client/Context.d.ts.map +1 -1
  20. package/types/client/Plugin.d.ts +42 -41
  21. package/types/client/Plugin.d.ts.map +1 -1
  22. package/types/client/PluginManager.d.ts +26 -11
  23. package/types/client/PluginManager.d.ts.map +1 -1
  24. package/types/client/SharedState.d.ts +1 -1
  25. package/types/client/SharedState.d.ts.map +1 -1
  26. package/types/client/SharedStateCollection.d.ts +41 -0
  27. package/types/client/SharedStateCollection.d.ts.map +1 -0
  28. package/types/client/Socket.d.ts +41 -30
  29. package/types/client/Socket.d.ts.map +1 -1
  30. package/types/client/StateManager.d.ts +1 -1
  31. package/types/client/StateManager.d.ts.map +1 -1
  32. package/types/client/index.d.ts +0 -8
  33. package/types/common/BasePlugin.d.ts +24 -19
  34. package/types/common/BasePlugin.d.ts.map +1 -1
  35. package/types/common/BasePluginManager.d.ts +17 -5
  36. package/types/common/BasePluginManager.d.ts.map +1 -1
  37. package/types/common/BaseSharedState.d.ts +100 -29
  38. package/types/common/BaseSharedState.d.ts.map +1 -1
  39. package/types/common/BaseSharedStateCollection.d.ts +183 -0
  40. package/types/common/BaseSharedStateCollection.d.ts.map +1 -0
  41. package/types/common/BaseStateManager.d.ts +83 -18
  42. package/types/common/BaseStateManager.d.ts.map +1 -1
  43. package/types/common/BatchedTransport.d.ts +21 -0
  44. package/types/common/BatchedTransport.d.ts.map +1 -0
  45. package/types/common/ParameterBag.d.ts +61 -40
  46. package/types/common/ParameterBag.d.ts.map +1 -1
  47. package/types/common/PromiseStore.d.ts +11 -0
  48. package/types/common/PromiseStore.d.ts.map +1 -0
  49. package/types/common/SharedStatePrivate.d.ts +4 -3
  50. package/types/common/SharedStatePrivate.d.ts.map +1 -1
  51. package/types/common/constants.d.ts +10 -1
  52. package/types/common/constants.d.ts.map +1 -1
  53. package/types/common/logger.d.ts +1 -1
  54. package/types/common/sockets-utils.d.ts.map +1 -1
  55. package/types/common/version.d.ts +3 -0
  56. package/types/common/version.d.ts.map +1 -0
  57. package/types/server/Client.d.ts +5 -0
  58. package/types/server/Client.d.ts.map +1 -1
  59. package/types/server/Context.d.ts +162 -22
  60. package/types/server/Context.d.ts.map +1 -1
  61. package/types/server/ContextManager.d.ts +4 -4
  62. package/types/server/ContextManager.d.ts.map +1 -1
  63. package/types/server/Plugin.d.ts +56 -55
  64. package/types/server/Plugin.d.ts.map +1 -1
  65. package/types/server/PluginManager.d.ts +26 -6
  66. package/types/server/PluginManager.d.ts.map +1 -1
  67. package/types/server/Server.d.ts +207 -70
  68. package/types/server/Server.d.ts.map +1 -1
  69. package/types/server/SharedState.d.ts +1 -1
  70. package/types/server/SharedState.d.ts.map +1 -1
  71. package/types/server/SharedStateCollection.d.ts +41 -0
  72. package/types/server/SharedStateCollection.d.ts.map +1 -0
  73. package/types/server/Socket.d.ts +93 -57
  74. package/types/server/Socket.d.ts.map +1 -1
  75. package/types/server/Sockets.d.ts +32 -25
  76. package/types/server/Sockets.d.ts.map +1 -1
  77. package/types/server/StateManager.d.ts +242 -27
  78. package/types/server/StateManager.d.ts.map +1 -1
  79. package/types/server/audit-network-latency.worker.d.ts +2 -1
  80. package/types/server/audit-schema.d.ts +8 -8
  81. package/types/server/crypto.d.ts +3 -0
  82. package/types/server/crypto.d.ts.map +1 -0
  83. package/types/server/index.d.ts +0 -4
  84. package/types/common/promise-store.d.ts +0 -4
  85. package/types/common/promise-store.d.ts.map +0 -1
  86. package/types/common/utils.d.ts +0 -5
  87. package/types/common/utils.d.ts.map +0 -1
@@ -1,39 +1,42 @@
1
- import { Worker } from 'node:worker_threads';
2
- import querystring from 'querystring';
3
- import { default as WebSocket, WebSocketServer } from 'ws';
1
+ import querystring from 'node:querystring';
2
+ import {
3
+ Worker,
4
+ } from 'node:worker_threads';
4
5
 
5
- import Socket from './Socket.js';
6
+ import {
7
+ default as WebSocket,
8
+ WebSocketServer,
9
+ } from 'ws';
10
+
11
+ import Socket, {
12
+ kSocketTerminate,
13
+ } from './Socket.js';
14
+
15
+ // @note - fs.readFileSync creates some cwd() issues...
6
16
  import networkLatencyWorker from './audit-network-latency.worker.js';
7
17
 
8
- // this crashes when bundling server to cjs module for Max, fallback to cjs worker
9
- // const __dirname = fileURLToPath(new URL('.', import.meta.url));
18
+ export const kSocketsRemoveFromAllRooms = Symbol('soundworks:sockets-remove-from-all-rooms');
19
+ export const kSocketsLatencyStatsWorker = Symbol('soundworks:sockets-latency-stats-worker');
20
+ export const kSocketsDebugPreventHeartBeat = Symbol('soundworks:sockets-debug-prevent-heartbeat');
10
21
 
11
22
  /**
12
- * Manager all {@link server.Socket} instances.
23
+ * Manage all {@link server.Socket} instances.
13
24
  *
14
- * Most of the time, you shouldn't have to use this class instance directely, but
15
- * it could be usefull in some situations, for broadcasting messages, creating rooms, etc.
25
+ * _Important: In most cases, you should consider using a {@link client.SharedState}
26
+ * rather than directly using the Socket instance._
16
27
  *
17
28
  * @memberof server
18
29
  */
19
30
  class Sockets {
31
+ #wsServer = null;
32
+ #rooms = new Map();
33
+
20
34
  constructor() {
21
- /** @private */
22
- this._wss = null;
23
- /** @private */
24
- this._rooms = new Map();
25
- // The special `'*'` romm stores all current connections.
26
- this._rooms.set('*', new Set());
27
- /** @private */
28
- this._initializationCache = new Map();
29
-
30
- /** @private */
31
- this._latencyStatsWorker = null; // protected - used in Socket instances
32
- /** @private */
33
- this._auditState = null;
34
-
35
- /** @private */
36
- this._DEBUG_PREVENT_HEARTBEAT = false;
35
+ // Init special `'*'` room which stores all current connections.
36
+ this.#rooms.set('*', new Set());
37
+
38
+ this[kSocketsLatencyStatsWorker] = null;
39
+ this[kSocketsDebugPreventHeartBeat] = false;
37
40
  }
38
41
 
39
42
  /**
@@ -44,15 +47,15 @@ class Sockets {
44
47
  * @private
45
48
  */
46
49
  async start(server, config, onConnectionCallback) {
47
- // init audit stuff for network latency estimation
48
- // @see note about __dirname
49
- // const workerPathname = path.join(__dirname, 'audit-network-latency.worker.js');
50
- this._latencyStatsWorker = new Worker(networkLatencyWorker, { eval: true });
51
- this._auditState = await server.getAuditState();
50
+ // Audit for network latency estimation, the worker is written in cjs so that we
51
+ // can make builds for Max, move back to modules once Max support modules
52
+ this[kSocketsLatencyStatsWorker] = new Worker(networkLatencyWorker, { eval: true });
52
53
 
53
- this._auditState.onUpdate(updates => {
54
+ const auditState = await server.getAuditState();
55
+
56
+ auditState.onUpdate(updates => {
54
57
  if ('averageNetworkLatencyWindow' in updates || 'averageNetworkLatencyPeriod' in updates) {
55
- this._latencyStatsWorker.postMessage({
58
+ this[kSocketsLatencyStatsWorker].postMessage({
56
59
  type: 'config',
57
60
  value: {
58
61
  averageLatencyWindow: updates.averageNetworkLatencyWindow,
@@ -62,137 +65,104 @@ class Sockets {
62
65
  }
63
66
  }, true);
64
67
 
65
- this._latencyStatsWorker.on('message', msg => {
68
+ this[kSocketsLatencyStatsWorker].on('message', msg => {
66
69
  if (msg.type === 'computed-average-latency') {
67
- this._auditState.set({ averageNetworkLatency: msg.value });
70
+ auditState.set({ averageNetworkLatency: msg.value });
68
71
  }
69
72
  });
70
73
 
71
- // init ws server
72
- this._wss = new WebSocketServer({
74
+ // Init ws server
75
+ this.#wsServer = new WebSocketServer({
73
76
  noServer: true,
74
- path: `/${config.path}`, // @note - update according to existing config files (aka cosima-apps)
77
+ path: `/${config.path}`,
75
78
  });
76
79
 
77
- this._wss.on('connection', (ws, req) => {
78
- const queryString = querystring.decode(req.url.split('?')[1]);
79
- const { role, key, token } = queryString;
80
- const binary = !!(parseInt(queryString.binary));
81
-
82
- if (binary) {
83
- ws.binaryType = 'arraybuffer';
84
- }
85
-
86
- if (!this._initializationCache.has(key)) {
87
- this._initializationCache.set(key, { ws, binary });
88
- } else {
89
- const cached = this._initializationCache.get(key);
90
- this._initializationCache.delete(key);
80
+ this.#wsServer.on('connection', (ws, req) => {
81
+ const { role, token } = querystring.parse(req.url.split('?')[1]);
82
+ const socket = new Socket(ws, this);
91
83
 
92
- // should be in order, but just to be sure
93
- const stringWs = cached.binary ? ws : cached.ws;
94
- const binaryWs = cached.binary ? cached.ws : ws;
95
- const socket = new Socket(stringWs, binaryWs, this._rooms, this, config);
84
+ socket.addToRoom('*');
85
+ socket.addToRoom(role);
96
86
 
97
- socket.addToRoom('*');
98
- socket.addToRoom(role);
99
-
100
- onConnectionCallback(role, socket, token);
101
- }
87
+ onConnectionCallback(role, socket, token);
102
88
  });
103
89
 
104
- // check if client can connect
90
+ // Prevent socket with protected role to connect is token is invalid
105
91
  server.httpServer.on('upgrade', async (req, socket, head) => {
106
- const queryString = querystring.decode(req.url.split('?')[1]);
107
-
108
- const { role, token } = queryString;
92
+ const { role, token } = querystring.parse(req.url.split('?')[1]);
109
93
 
110
94
  if (server.isProtected(role)) {
111
- // we don't have any ip in the upgrade request, so we just check the
112
- // connection token is pending
113
- const allowed = server.isValidConnectionToken(token);
114
-
115
- if (!allowed) {
95
+ // we don't have any IP in the upgrade request object,
96
+ // so we just check the connection token is pending and valid
97
+ if (!server.isValidConnectionToken(token)) {
116
98
  socket.destroy('not allowed');
117
99
  }
118
100
  }
119
101
 
120
- this._wss.handleUpgrade(req, socket, head, (ws) => {
121
- this._wss.emit('connection', ws, req);
102
+ this.#wsServer.handleUpgrade(req, socket, head, (ws) => {
103
+ this.#wsServer.emit('connection', ws, req);
122
104
  });
123
105
  });
124
106
  }
125
107
 
126
108
  /**
127
- * Terminate all existing sockets
128
- *
109
+ * Terminate all existing sockets.
129
110
  * @private
130
111
  */
131
112
  terminate() {
132
113
  // terminate stat worker thread
133
- this._latencyStatsWorker.terminate();
114
+ this[kSocketsLatencyStatsWorker].terminate();
134
115
  // clean sockets
135
- const sockets = this._rooms.get('*');
136
- sockets.forEach(socket => socket.terminate());
116
+ const sockets = this.#rooms.get('*');
117
+ sockets.forEach(socket => socket[kSocketTerminate]());
137
118
  }
138
119
 
139
- /** @private */
140
- _broadcast(binary, roomIds, excludeSocket, channel, ...args) {
141
- const method = binary ? 'sendBinary' : 'send';
142
- let targets = new Set();
143
-
144
- if (typeof roomIds === 'string' || Array.isArray(roomIds)) {
145
- if (typeof roomIds === 'string') {
146
- roomIds = [roomIds];
147
- }
148
-
149
- roomIds.forEach(roomId => {
150
- if (this._rooms.has(roomId)) {
151
- const room = this._rooms.get(roomId);
152
- room.forEach(socket => targets.add(socket));
153
- }
154
- });
155
- } else {
156
- targets = this._rooms.get('*');
120
+ /**
121
+ * Remove given socket from all rooms.
122
+ */
123
+ [kSocketsRemoveFromAllRooms](socket) {
124
+ for (let [_, room] of this.#rooms) {
125
+ room.delete(socket);
157
126
  }
158
-
159
- targets.forEach(socket => {
160
- if (socket.ws.readyState === WebSocket.OPEN) {
161
- if (excludeSocket !== null) {
162
- if (socket !== excludeSocket) {
163
- socket[method](channel, ...args);
164
- }
165
- } else {
166
- socket[method](channel, ...args);
167
- }
168
- }
169
- });
170
127
  }
171
128
 
172
129
  /**
173
- * Add a socket to a room
130
+ * Add a socket to a room.
131
+ *
132
+ * _Note that in most cases, you should use a shared state instead_
174
133
  *
175
134
  * @param {server.Socket} socket - Socket to add to the room.
176
135
  * @param {String} roomId - Id of the room.
177
136
  */
178
137
  addToRoom(socket, roomId) {
179
- socket.addToRoom(roomId);
138
+ if (!this.#rooms.has(roomId)) {
139
+ this.#rooms.set(roomId, new Set());
140
+ }
141
+
142
+ const room = this.#rooms.get(roomId);
143
+ room.add(socket);
180
144
  }
181
145
 
182
146
  /**
183
- * Remove a socket from a room
147
+ * Remove a socket from a room.
148
+ *
149
+ * _Note that in most cases, you should use a shared state instead_
184
150
  *
185
151
  * @param {server.Socket} socket - Socket to remove from the room.
186
152
  * @param {String} roomId - Id of the room.
187
153
  */
188
154
  removeFromRoom(socket, roomId) {
189
- socket.removeFromRoom(roomId);
155
+ if (this.#rooms.has(roomId)) {
156
+ const room = this.#rooms.get(roomId);
157
+ room.delete(socket);
158
+ }
190
159
  }
191
160
 
192
161
  /**
193
- * Send a message of JSON compatible data types to all client of given room(s).
194
- * If no room is specified, the message is sent to all clients.
162
+ * Send a message to all clients os given room(s). If no room is specified,
163
+ * the message is sent to all clients.
195
164
  *
165
+ * _Note that in most cases, you should use a shared state instead_
196
166
  *
197
167
  * @param {String|Array} roomsIds - Ids of the rooms that must receive
198
168
  * the message. If `null` the message is sent to all clients.
@@ -203,22 +173,28 @@ class Sockets {
203
173
  * JSON compatible data types (i.e. string, number, boolean, object, array and null).
204
174
  */
205
175
  broadcast(roomIds, excludeSocket, channel, ...args) {
206
- this._broadcast(false, roomIds, excludeSocket, channel, ...args);
207
- }
176
+ const targets = new Set();
208
177
 
209
- /**
210
- * Send a binary message to all client of given room(s). If no room is specified
211
- * specified, the message is sent to all clients.
212
- *
213
- * @param {String|Array} roomsIds - Ids of the rooms that must receive
214
- * the message. If `null` the message is sent to all clients.
215
- * @param {server.Socket} excludeSocket - Optionnal socket to ignore when
216
- * broadcasting the message, typically the client at the origin of the message.
217
- * @param {string} channel - Channel name.
218
- * @param {TypedArray} typedArray - Binary data to be sent.
219
- */
220
- broadcastBinary(roomIds, excludeSocket, channel, typedArray) {
221
- this._broadcast(true, roomIds, excludeSocket, channel, typedArray);
178
+ if (typeof roomIds === 'string' || Array.isArray(roomIds)) {
179
+ if (typeof roomIds === 'string') {
180
+ roomIds = [roomIds];
181
+ }
182
+
183
+ roomIds.forEach(roomId => {
184
+ if (this.#rooms.has(roomId)) {
185
+ const room = this.#rooms.get(roomId);
186
+ room.forEach(socket => targets.add(socket));
187
+ }
188
+ });
189
+ } else {
190
+ targets = this.#rooms.get('*');
191
+ }
192
+
193
+ targets.forEach(socket => {
194
+ if (socket.readyState === WebSocket.OPEN && socket !== excludeSocket) {
195
+ socket.send(channel, ...args);
196
+ }
197
+ });
222
198
  }
223
199
  }
224
200
 
@@ -1,5 +1,6 @@
1
- // NOTICE: we use this syntax so that the server can be bundled to cjs
2
- // with esbuild, so we can ship a cjs server bundle into Max.
1
+ // @note - We use this common js syntax so that the server can be bundled to cjs
2
+ // which allows to build a server that can be accepted by Max `node.script`
3
+ //
3
4
  // Should move back to regular esm module once Max has fixed its loader
4
5
  export default `
5
6
  const { parentPort } = require('node:worker_threads');
@@ -11,6 +12,7 @@ let averageLatencyPeriod = 2;
11
12
  let intervalId = null;
12
13
  let meanLatency = 0;
13
14
 
15
+ // workaround that sc-utils is pure emascript module
14
16
  let getTime;
15
17
  let inited = new Promise(async (resolve) => {
16
18
  module = await import('@ircam/sc-utils');
@@ -25,7 +27,6 @@ parentPort.on('message', async msg => {
25
27
  averageLatencyPeriod = msg.value.averageLatencyPeriod;
26
28
 
27
29
  await inited;
28
-
29
30
  // launch compute in its own loop so that the number of computation is
30
31
  // decoupled from the number of connected clients
31
32
  clearInterval(intervalId);
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2014-present IRCAM – Centre Pompidou (France, Paris)
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+
1
7
  /**
2
8
  * Server-side part of the *soundworks* framework.
3
9
  *
@@ -1,6 +1,28 @@
1
1
  export default Client;
2
2
  /**
3
- * The `Client` class is the main entry point for the client-side of soundworks
3
+ * Configuration object for a client running in a browser runtime.
4
+ */
5
+ export type ClientConfig = any;
6
+ /**
7
+ * Configuration object for a client running in a browser runtime.
8
+ *
9
+ * @typedef ClientConfig
10
+ * @memberof client
11
+ * @type {object}
12
+ * @property {string} role - Role of the client in the application (e.g. 'player', 'controller').
13
+ * @property {object} [app] - Application configration object.
14
+ * @property {string} [app.name=''] - Name of the application.
15
+ * @property {string} [app.author=''] - Name of the author.
16
+ * @property {object} [env] - Environment configration object.
17
+ * @property {boolean} env.useHttps - Define if the websocket should use secure connection.
18
+ * @property {boolean} [env.serverAddress=''] - Address the socket server. Mandatory for
19
+ * node clients. For browser clients, use `window.location.domain` as fallback if empty.
20
+ * @property {boolean} env.port - Port of the socket server.
21
+ * @property {string} [env.websockets={}] - Configuration options for websockets.
22
+ * @property {string} [env.subpath=''] - If running behind a proxy, path to the application.
23
+ */
24
+ /**
25
+ * The `Client` class is the main entry point for the client-side of a soundworks
4
26
  * application.
5
27
  *
6
28
  * A `Client` instance allows to access soundworks components such as {@link client.StateManager},
@@ -20,11 +42,16 @@ export default Client;
20
42
  */
21
43
  declare class Client {
22
44
  /**
23
- * @param {client.BrowserClientConfig|client.NodeClientConfig} config -
24
- * Configuration of the soundworks client.
45
+ * @param {client.ClientConfig} config - Configuration of the soundworks client.
25
46
  * @throws Will throw if the given config object is invalid.
26
47
  */
27
- constructor(config: client.BrowserClientConfig | client.NodeClientConfig);
48
+ constructor(config: client.ClientConfig);
49
+ /**
50
+ * package version
51
+ * @type string
52
+ * @readonly
53
+ */
54
+ readonly version: string;
28
55
  /**
29
56
  * Role of the client in the application.
30
57
  *
@@ -34,9 +61,9 @@ declare class Client {
34
61
  /**
35
62
  * Configuration object.
36
63
  *
37
- * @type {client.BrowserClientConfig|client.NodeClientConfig}
64
+ * @type {client.ClientConfig}
38
65
  */
39
- config: client.BrowserClientConfig | client.NodeClientConfig;
66
+ config: client.ClientConfig;
40
67
  /**
41
68
  * Session id of the client (incremeted positive number), generated and
42
69
  * retrieved by the server during `client.init`. The counter is reset when
@@ -99,6 +126,11 @@ declare class Client {
99
126
  * @type {string}
100
127
  */
101
128
  status: string;
129
+ /**
130
+ * Token of the client if connected through HTTP authentication.
131
+ * @private
132
+ */
133
+ private token;
102
134
  /** @private */
103
135
  private _onStatusChangeCallbacks;
104
136
  /** @private */
@@ -136,8 +168,9 @@ declare class Client {
136
168
  * method if it has not been called manually.
137
169
  *
138
170
  * What it does:
139
- * - optionnaly call {@link client.Client#init}
140
- * - starts all the already created contexts (see {@link client.Context})
171
+ * - implicitly call {@link client.Client#init} if not done manually
172
+ * - start all created contexts. For that to happen, you will have to call `client.init`
173
+ * manually and instantiate the contexts between `client.init()` and `client.start()`
141
174
  *
142
175
  * @example
143
176
  * import { Client } from '@soundworks/core/client.js'
@@ -1 +1 @@
1
- {"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../../src/client/Client.js"],"names":[],"mappings":";AAeA;;;;;;;;;;;;;;;;;;GAkBG;AACH;IACE;;;;OAIG;IACH,oBAJW,oDAAkD,EA0I5D;IApGC;;;;OAIG;IACH,MAFU,MAAM,CAEO;IAEvB;;;;OAIG;IACH,QAFU,oDAAkD,CAExC;IAYpB;;;;;;OAMG;IACH,IAFU,MAAM,CAEF;IAEd;;;;;OAKG;IACH,MAFU,MAAM,CAEA;IAEhB;;;;;;OAMG;IACH,sBAA0B;IAE1B;;;;OAIG;IACH,QAFU,MAAM,CAE8B;IAE9C;;;;;;;OAOG;IACH,sCAA0C;IAE1C;;;;;;;OAOG;IACH,oCAA4C;IAE5C;;;;;;;OAOG;IACH,kCAAwB;IAExB;;;;OAIG;IACH,QAFU,MAAM,CAEI;IAEpB,eAAe;IACf,iCAAyC;IACzC,eAAe;IACf,oBAAuB;IAKzB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,sBA6DC;IAED;;;;;;;;;;;;;;OAcG;IACH,uBAmBC;IAED;;;;;;;;;;;;;;;OAeG;IACH,sBAUC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,iBAPa,2BAA2B,CAiBvC;IAED;;;;;OAKG;IACH,6CAIC;IAED,eAAe;IACf,wBAgBC;CACF"}
1
+ {"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../../src/client/Client.js"],"names":[],"mappings":";;;;;AAeA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH;IACE;;;OAGG;IACH,yCAmJC;IAjHC;;;;OAIG;IACH,kBAHS,MAAM,CAGO;IAEtB;;;;OAIG;IACH,MAFU,MAAM,CAEO;IAEvB;;;;OAIG;IACH,4BAAoB;IAYpB;;;;;;OAMG;IACH,IAFU,MAAM,CAEF;IAEd;;;;;OAKG;IACH,MAFU,MAAM,CAEA;IAEhB;;;;;;OAMG;IACH,sBAA0B;IAE1B;;;;OAIG;IACH,QAFU,MAAM,CAE8B;IAE9C;;;;;;;OAOG;IACH,sCAA0C;IAE1C;;;;;;;OAOG;IACH,oCAA4C;IAE5C;;;;;;;OAOG;IACH,kCAAsC;IAEtC;;;;OAIG;IACH,QAFU,MAAM,CAEI;IAEpB;;;OAGG;IACH,cAAiB;IAEjB,eAAe;IACf,iCAAyC;IACzC,eAAe;IACf,oBAAuB;IAKzB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,sBA8EC;IAED;;;;;;;;;;;;;;;OAeG;IACH,uBAmBC;IAED;;;;;;;;;;;;;;;OAeG;IACH,sBAUC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,iBAPa,2BAA2B,CAiBvC;IAED;;;;;OAKG;IACH,6CAIC;IAED,eAAe;IACf,wBAgBC;CACF"}
@@ -51,39 +51,66 @@ declare class Context {
51
51
  constructor(client: client.Client);
52
52
  /**
53
53
  * The soundworks client instance.
54
+ * @type {client.Client}
55
+ * @readonly
54
56
  */
55
- client: Client;
57
+ readonly client: client.Client;
56
58
  /**
57
59
  * Status of the context, i.e. 'idle', 'inited', 'started', 'errored'
60
+ * @type {string}
61
+ * @readonly
58
62
  */
59
- status: string;
63
+ readonly status: string;
60
64
  /**
61
- * Name of the context. Defaults to the class name, override to use a user-defined name.
65
+ * Optionnal user-defined name of the context (defaults to the class name).
62
66
  *
63
- * @returns {string} - Name of the context.
67
+ * The context manager will match the client-side and server-side contexts based
68
+ * on this name. If the {@link server.ContextManager} don't find a corresponding
69
+ * user-defined context with the same name, it will use a default (noop) context.
70
+ *
71
+ * @readonly
72
+ * @type {string}
64
73
  * @example
74
+ * // server-side and client-side contexts are matched based on their respective `name`
65
75
  * class MyContext extends Context {
66
76
  * get name() {
67
77
  * return 'my-user-defined-context-name';
68
78
  * }
69
79
  * }
70
80
  */
71
- get name(): string;
81
+ readonly get name(): string;
72
82
  /**
73
- * Start the context. This method is automatically called when `await client.start()`
74
- * is called, or lazilly called when entering the context (i.e. `context.enter()`)
75
- * if the context has been created after `client.start()`.
83
+ * Start the context. This method is lazilly called when the client enters the
84
+ * context for the first time (cf. ${client.Context#enter}). If you know some
85
+ * some heavy and/or potentially long job has to be done when starting the context
86
+ * (e.g. call to a web service) it may be a good practice to call it explicitely.
87
+ *
88
+ * This method should be implemented to perform operations that are valid for the
89
+ * whole lifetime of the context, regardless the client enters or exits the context.
90
+ *
91
+ * @example
92
+ * import { Context } from '@soundworks/core/client.js';
93
+ *
94
+ * class MyContext extends Context {
95
+ * async start() {
96
+ * await super.start();
97
+ * await this.doSomeLongJob();
98
+ * }
99
+ * }
76
100
  *
77
- * In some situation, you might want to implement this method to handle application
78
- * wise behavior regardeless the client enters or exists the context.
101
+ * // Instantiate the context
102
+ * const myContext = new Context(client);
103
+ * // manually start the context to perform the long operation before the client
104
+ * // enters the context.
105
+ * await myContext.start();
79
106
  */
80
107
  start(): Promise<void>;
81
108
  /**
82
109
  * Stop the context. This method is automatically called when `await client.stop()`
83
- * is called.
110
+ * is called. It should be used to cleanup context wise operations made in `start()`
111
+ * (e.g. destroy the reusable audio graph).
84
112
  *
85
- * In some situation, you might want to implement this method to handle application
86
- * wise behavior regardeless the client enters or exists the context.
113
+ * _WARNING: this method should never be called manually._
87
114
  */
88
115
  stop(): Promise<void>;
89
116
  /**
@@ -135,5 +162,4 @@ declare class Context {
135
162
  */
136
163
  exit(): Promise<any>;
137
164
  }
138
- import Client from "./Client.js";
139
165
  //# sourceMappingURL=Context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Context.d.ts","sourceRoot":"","sources":["../../src/client/Context.js"],"names":[],"mappings":";AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH;IACE;;;OAGG;IACH,mCAgDC;IA3CC;;OAEG;IACH,eAAoB;IAEpB;;OAEG;IACH,eAAoB;IAqCtB;;;;;;;;;;OAUG;IACH,mBAEC;IAED;;;;;;;OAOG;IACH,uBAAgB;IAEhB;;;;;;OAMG;IACH,sBAAe;IAEf;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,sBAeC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,qBAUC;CACF"}
1
+ {"version":3,"file":"Context.d.ts","sourceRoot":"","sources":["../../src/client/Context.js"],"names":[],"mappings":";AAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH;IACE;;;OAGG;IACH,mCAoDC;IA/CC;;;;OAIG;IACH,+BAAoB;IAEpB;;;;OAIG;IACH,iBAHU,MAAM,CAGI;IAqCtB;;;;;;;;;;;;;;;;OAgBG;IACH,4BAEC;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,uBAAgB;IAEhB;;;;;;OAMG;IACH,sBAAe;IAEf;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,sBAeC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,qBAUC;CACF"}
@@ -3,51 +3,52 @@ export namespace client {
3
3
  /**
4
4
  * ~onStateChangeCallback
5
5
  */
6
- export type Plugin = (#state: client.Plugin) => any;
7
- /**
8
- * Callback executed when the plugin state is updated.
9
- *
10
- * @callback client.Plugin~onStateChangeCallback
11
- * @param {client.Plugin#state} state - Current state of the plugin.
12
- */
6
+ type Plugin = (#state: client.Plugin) => any;
7
+ }
8
+ /**
9
+ * Callback executed when the plugin state is updated.
10
+ *
11
+ * @callback client.Plugin~onStateChangeCallback
12
+ * @param {client.Plugin#state} state - Current state of the plugin.
13
+ */
14
+ /**
15
+ * Delete the registered {@link client.Plugin~onStateChangeCallback}.
16
+ *
17
+ * @callback client.Plugin~deleteOnStateChangeCallback
18
+ */
19
+ /**
20
+ * Base class to extend in order to create the client-side counterpart of a
21
+ * `soundworks` plugin.
22
+ *
23
+ * In the `soundworks` paradigm, a plugin is a component that allows to extend
24
+ * the framework capabilities by encapsulating common and reusable logic in
25
+ * an application wise perspective. For example, plugins are available to handle
26
+ * clock synchronization, to deal with the file system, etc. Plugin should always
27
+ * have both a client-side and a server-side part.
28
+ *
29
+ * See [https://soundworks.dev/guide/ecosystem](https://soundworks.dev/guide/ecosystem)
30
+ * for more informations on the available plugins.
31
+ *
32
+ * _Creating new plugins should be considered an advanced usage._
33
+ *
34
+ * @memberof client
35
+ * @extends BasePlugin
36
+ * @inheritdoc
37
+ */
38
+ declare class Plugin extends BasePlugin {
13
39
  /**
14
- * Delete the registered {@link client.Plugin~onStateChangeCallback}.
15
- *
16
- * @callback client.Plugin~deleteOnStateChangeCallback
40
+ * @param {client.Client} client - The soundworks client instance.
41
+ * @param {string} id - User defined id of the plugin as defined in
42
+ * {@link client.PluginManager#register}.
17
43
  */
44
+ constructor(client: client.Client, id: string);
18
45
  /**
19
- * Base class to extend in order to create new `soundworks` plugins.
20
- *
21
- * In the `soundworks` paradigm, a plugin is a component that allows to extend
22
- * the framework capabilities by encapsulating common and reusable logic in
23
- * an application wise perspective. For example, plugins are available to handle
24
- * clock synchronization, to deal with the file system, etc. Plugin should always
25
- * have both a client-side and a server-side part.
26
- *
27
- * See [https://soundworks.dev/guide/ecosystem](https://soundworks.dev/guide/ecosystem)
28
- * for more informations on the available plugins.
29
- *
30
- * _Creating new plugins should be considered an advanced usage._
46
+ * Instance of soundworks client.
31
47
  *
32
- * @memberof client
33
- * @extends BasePlugin
34
- * @inheritdoc
48
+ * @type {client.Client}
49
+ * @see {@link client.Client}
35
50
  */
36
- class Plugin extends BasePlugin {
37
- /**
38
- * @param {client.Client} client - The soundworks client instance.
39
- * @param {string} id - User defined id of the plugin as defined in
40
- * {@link client.PluginManager#register}.
41
- */
42
- constructor(client: client.Client, id: string);
43
- /**
44
- * Instance of soundworks client.
45
- *
46
- * @type {client.Client}
47
- * @see {@link client.Client}
48
- */
49
- client: client.Client;
50
- }
51
+ client: client.Client;
51
52
  }
52
- import BasePlugin from "../common/BasePlugin.js";
53
+ import BasePlugin from '../common/BasePlugin.js';
53
54
  //# sourceMappingURL=Plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Plugin.d.ts","sourceRoot":"","sources":["../../src/client/Plugin.js"],"names":[],"mappings":";;;;;kCAMW,aAAa;IAJxB;;;;;OAKG;IAEH;;;;OAIG;IAEH;;;;;;;;;;;;;;;;;OAiBG;IACH;QACE;;;;WAIG;QACH,uCAHW,MAAM,EAahB;QAPC;;;;;WAKG;QACH,sBAAoB;KAevB"}
1
+ {"version":3,"file":"Plugin.d.ts","sourceRoot":"","sources":["../../src/client/Plugin.js"],"names":[],"mappings":";;;;;2BAMW,aAAa;;AAJxB;;;;;GAKG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH;IACE;;;;OAIG;IACH,uCAHW,MAAM,EAahB;IAPC;;;;;OAKG;IACH,sBAAoB;CAevB;uBAhEsB,yBAAyB"}