node-osc 11.1.0 → 11.2.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/.gitattributes +11 -0
- package/.github/workflows/bump-version.yml +2 -0
- package/.github/workflows/nodejs.yml +3 -0
- package/LICENSE +201 -165
- package/README.md +135 -42
- package/dist/lib/Bundle.js +66 -0
- package/dist/lib/Client.js +137 -22
- package/dist/lib/Message.js +87 -1
- package/dist/lib/Server.js +117 -6
- package/dist/lib/index.js +3 -0
- package/dist/lib/internal/decode.js +4 -4
- package/{lib/internal/osc.mjs → dist/lib/osc.js} +94 -23
- package/dist/test/lib/osc.js +395 -0
- package/dist/test/test-client.js +152 -0
- package/dist/test/test-e2e.js +9 -3
- package/dist/test/test-encode-decode.js +849 -0
- package/dist/test/test-error-handling.js +116 -0
- package/dist/test/test-osc-internal.js +399 -41
- package/dist/test/test-promises.js +250 -0
- package/dist/test/test-types.js +42 -0
- package/dist/test/util.js +15 -8
- package/docs/API.md +477 -0
- package/docs/GUIDE.md +605 -0
- package/examples/README.md +119 -0
- package/examples/async-await.mjs +57 -0
- package/examples/bundle-example.mjs +92 -0
- package/examples/client.js +22 -5
- package/examples/error-handling.mjs +152 -0
- package/examples/esm.mjs +21 -0
- package/examples/server.js +16 -0
- package/jsdoc.json +16 -0
- package/lib/Bundle.mjs +66 -0
- package/lib/Client.mjs +137 -22
- package/lib/Message.mjs +87 -1
- package/lib/Server.mjs +117 -6
- package/lib/index.mjs +1 -0
- package/lib/internal/decode.mjs +4 -4
- package/{dist/lib/internal/osc.js → lib/osc.mjs} +71 -7
- package/package.json +12 -10
- package/rollup.config.mjs +48 -37
- package/scripts/generate-docs.mjs +229 -0
- package/test/fixtures/types/test-cjs-types.ts +19 -0
- package/test/fixtures/types/test-esm-types.ts +35 -0
- package/test/fixtures/types/tsconfig-cjs.test.json +17 -0
- package/test/fixtures/types/tsconfig-esm.test.json +17 -0
- package/test/test-bundle.mjs +0 -1
- package/test/test-client.mjs +152 -0
- package/test/test-e2e.mjs +9 -3
- package/test/test-encode-decode.mjs +847 -0
- package/test/test-error-handling.mjs +115 -0
- package/test/test-osc-internal.mjs +400 -42
- package/test/test-promises.mjs +249 -0
- package/test/test-types.mjs +39 -0
- package/test/util.mjs +15 -8
- package/tsconfig.json +45 -0
- package/types/Bundle.d.mts +70 -0
- package/types/Bundle.d.mts.map +1 -0
- package/types/Client.d.mts +101 -0
- package/types/Client.d.mts.map +1 -0
- package/types/Message.d.mts +84 -0
- package/types/Message.d.mts.map +1 -0
- package/types/Server.d.mts +98 -0
- package/types/Server.d.mts.map +1 -0
- package/types/index.d.mts +6 -0
- package/types/index.d.mts.map +1 -0
- package/types/internal/decode.d.mts +4 -0
- package/types/internal/decode.d.mts.map +1 -0
- package/types/osc.d.mts +66 -0
- package/types/osc.d.mts.map +1 -0
package/README.md
CHANGED
|
@@ -3,19 +3,84 @@
|
|
|
3
3
|
A no frills [Open Sound Control](http://opensoundcontrol.org) client and server.
|
|
4
4
|
Heavily inspired by [pyOSC](https://trac.v2.nl/wiki/pyOSC).
|
|
5
5
|
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
6
8
|
Install using npm
|
|
7
9
|
|
|
8
|
-
```
|
|
10
|
+
```bash
|
|
9
11
|
npm install node-osc
|
|
10
12
|
```
|
|
11
13
|
|
|
12
|
-
##
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- 🚀 Simple and intuitive API
|
|
17
|
+
- 🔄 Both callback and async/await support
|
|
18
|
+
- 📦 Send and receive OSC messages and bundles
|
|
19
|
+
- 🌐 Works with both ESM and CommonJS
|
|
20
|
+
- 📘 TypeScript type definitions included (generated from JSDoc)
|
|
21
|
+
- 📝 Comprehensive documentation and examples
|
|
22
|
+
- ✅ Well tested and actively maintained
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Sending Messages
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
import { Client } from 'node-osc';
|
|
30
|
+
|
|
31
|
+
const client = new Client('127.0.0.1', 3333);
|
|
32
|
+
await client.send('/oscAddress', 200);
|
|
33
|
+
await client.close();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Receiving Messages
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import { Server } from 'node-osc';
|
|
40
|
+
|
|
41
|
+
const server = new Server(3333, '0.0.0.0');
|
|
42
|
+
|
|
43
|
+
server.on('message', (msg) => {
|
|
44
|
+
console.log(`Message: ${msg}`);
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Documentation
|
|
49
|
+
|
|
50
|
+
- 📚 **[API Documentation](./docs/API.md)** - Complete API reference generated from source code
|
|
51
|
+
- 📘 **[Guide](./docs/GUIDE.md)** - Best practices, error handling, and troubleshooting
|
|
52
|
+
- 📖 **[Examples](./examples/)** - Working examples for various use cases
|
|
13
53
|
|
|
14
|
-
|
|
54
|
+
## Compatibility
|
|
55
|
+
|
|
56
|
+
Written using ESM, supports CJS.
|
|
57
|
+
|
|
58
|
+
Supports the latest versions of Node.js 20, 22, and 24 in both ESM + CJS.
|
|
59
|
+
|
|
60
|
+
## TypeScript
|
|
61
|
+
|
|
62
|
+
TypeScript type definitions are included! No need to install `@types/node-osc`.
|
|
63
|
+
|
|
64
|
+
The types are automatically generated from JSDoc comments during the build process and included with the package. A single `.d.mts` type definition format is provided that works for both ESM and CommonJS consumers.
|
|
65
|
+
|
|
66
|
+
**Note:** If you previously installed `@types/node-osc`, you should uninstall it to avoid conflicts:
|
|
67
|
+
```bash
|
|
68
|
+
npm uninstall @types/node-osc
|
|
69
|
+
```
|
|
15
70
|
|
|
16
|
-
##
|
|
71
|
+
## More Examples
|
|
17
72
|
|
|
18
|
-
### Sending
|
|
73
|
+
### Sending with async/await
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
import { Client } from 'node-osc';
|
|
77
|
+
|
|
78
|
+
const client = new Client('127.0.0.1', 3333);
|
|
79
|
+
await client.send('/oscAddress', 200);
|
|
80
|
+
await client.close();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Sending with callbacks
|
|
19
84
|
|
|
20
85
|
```js
|
|
21
86
|
import { Client } from 'node-osc';
|
|
@@ -25,89 +90,117 @@ client.send('/oscAddress', 200, () => {
|
|
|
25
90
|
client.close();
|
|
26
91
|
});
|
|
27
92
|
```
|
|
28
|
-
|
|
29
|
-
### Listening for OSC messages
|
|
93
|
+
|
|
94
|
+
### Listening for OSC messages
|
|
30
95
|
|
|
31
96
|
```js
|
|
32
97
|
import { Server } from 'node-osc';
|
|
33
98
|
|
|
34
|
-
|
|
99
|
+
const oscServer = new Server(3333, '0.0.0.0', () => {
|
|
35
100
|
console.log('OSC Server is listening');
|
|
36
101
|
});
|
|
37
102
|
|
|
38
103
|
oscServer.on('message', function (msg) {
|
|
39
104
|
console.log(`Message: ${msg}`);
|
|
40
|
-
oscServer.close();
|
|
41
105
|
});
|
|
42
106
|
```
|
|
43
107
|
|
|
44
|
-
### Sending OSC bundles
|
|
108
|
+
### Sending OSC bundles
|
|
45
109
|
|
|
46
110
|
```js
|
|
47
111
|
import { Bundle, Client } from 'node-osc';
|
|
48
112
|
|
|
49
|
-
// a bundle without an explicit time tag
|
|
50
113
|
const bundle = new Bundle(['/one', 1], ['/two', 2], ['/three', 3]);
|
|
51
|
-
|
|
52
|
-
// a bundle with a timetag of 10
|
|
53
|
-
bundle.append(new Bundle(10, ['/four', 4]));
|
|
54
|
-
|
|
55
114
|
const client = new Client('127.0.0.1', 3333);
|
|
56
|
-
client.send(bundle)
|
|
115
|
+
await client.send(bundle);
|
|
116
|
+
await client.close();
|
|
57
117
|
```
|
|
58
118
|
|
|
59
|
-
### Listening for OSC bundles
|
|
119
|
+
### Listening for OSC bundles
|
|
60
120
|
|
|
61
121
|
```js
|
|
62
122
|
import { Server } from 'node-osc';
|
|
63
123
|
|
|
64
|
-
|
|
124
|
+
const oscServer = new Server(3333, '0.0.0.0', () => {
|
|
65
125
|
console.log('OSC Server is listening');
|
|
66
126
|
});
|
|
67
127
|
|
|
68
128
|
oscServer.on('bundle', function (bundle) {
|
|
69
|
-
bundle.elements.forEach((element
|
|
70
|
-
console.log(`Timestamp: ${bundle.timetag
|
|
129
|
+
bundle.elements.forEach((element) => {
|
|
130
|
+
console.log(`Timestamp: ${bundle.timetag}`);
|
|
71
131
|
console.log(`Message: ${element}`);
|
|
72
132
|
});
|
|
73
|
-
oscServer.close();
|
|
74
133
|
});
|
|
75
134
|
```
|
|
76
135
|
|
|
77
|
-
###
|
|
136
|
+
### Low-Level Encoding and Decoding
|
|
78
137
|
|
|
79
|
-
|
|
138
|
+
For advanced use cases, you can directly encode and decode OSC messages:
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
import { Message, encode, decode } from 'node-osc';
|
|
142
|
+
|
|
143
|
+
// Encode a message to binary
|
|
144
|
+
const message = new Message('/oscillator/frequency', 440);
|
|
145
|
+
const buffer = encode(message);
|
|
146
|
+
|
|
147
|
+
// Decode binary data back to a message
|
|
148
|
+
const decoded = decode(buffer);
|
|
149
|
+
console.log('Address:', decoded.address);
|
|
150
|
+
console.log('Value:', decoded.args[0].value);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
This is useful for:
|
|
154
|
+
- Sending OSC over non-UDP transports (WebSocket, TCP, HTTP)
|
|
155
|
+
- Storing OSC messages to files or databases
|
|
156
|
+
- Testing and debugging OSC implementations
|
|
157
|
+
- Building custom OSC routers or processors
|
|
158
|
+
|
|
159
|
+
See the **[API Documentation](./docs/API.md)** for complete details.
|
|
160
|
+
|
|
161
|
+
## CommonJS
|
|
162
|
+
|
|
163
|
+
Both callback and promise-based APIs work with CommonJS!
|
|
80
164
|
|
|
81
165
|
```js
|
|
82
166
|
const { Client, Server } = require('node-osc');
|
|
83
167
|
|
|
84
|
-
|
|
85
|
-
|
|
168
|
+
async function main() {
|
|
169
|
+
const server = new Server(3333, '0.0.0.0');
|
|
170
|
+
const client = new Client('127.0.0.1', 3333);
|
|
86
171
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
})
|
|
172
|
+
await new Promise((resolve) => {
|
|
173
|
+
server.on('listening', resolve);
|
|
174
|
+
});
|
|
90
175
|
|
|
91
|
-
server.on('message', (msg) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
});
|
|
176
|
+
server.on('message', (msg) => {
|
|
177
|
+
console.log(`Message: ${msg}`);
|
|
178
|
+
});
|
|
95
179
|
|
|
96
|
-
client.send('/hello', 'world'
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
180
|
+
await client.send('/hello', 'world');
|
|
181
|
+
await client.close();
|
|
182
|
+
await server.close();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
main();
|
|
100
186
|
```
|
|
101
187
|
|
|
102
|
-
##
|
|
188
|
+
## Examples
|
|
103
189
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
190
|
+
See the [examples](./examples/) directory for more usage examples:
|
|
191
|
+
- [client.js](./examples/client.js) - CommonJS client example
|
|
192
|
+
- [server.js](./examples/server.js) - CommonJS server example
|
|
193
|
+
- [esm.mjs](./examples/esm.mjs) - ESM example with callbacks
|
|
194
|
+
- [async-await.mjs](./examples/async-await.mjs) - ESM example with async/await
|
|
195
|
+
- [bundle-example.mjs](./examples/bundle-example.mjs) - Working with bundles
|
|
196
|
+
- [error-handling.mjs](./examples/error-handling.mjs) - Error handling patterns
|
|
107
197
|
|
|
108
|
-
|
|
198
|
+
## Contributing
|
|
109
199
|
|
|
200
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
110
201
|
|
|
111
202
|
## License
|
|
112
203
|
|
|
113
|
-
|
|
204
|
+
Apache-2.0
|
|
205
|
+
|
|
206
|
+
**Note:** This project was relicensed from LGPL-3.0-or-later to Apache-2.0 in December 2025.
|
package/dist/lib/Bundle.js
CHANGED
|
@@ -2,12 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
var Message = require('./Message.js');
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Convert array notation to Message object.
|
|
7
|
+
* @private
|
|
8
|
+
* @param {Array|Message|Bundle} element - The element to sanitize.
|
|
9
|
+
* @returns {Message|Bundle} The sanitized element.
|
|
10
|
+
*/
|
|
5
11
|
function sanitize(element) {
|
|
6
12
|
if (element instanceof Array) element = new Message(element[0], ...element.slice(1));
|
|
7
13
|
return element;
|
|
8
14
|
}
|
|
9
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Represents an OSC bundle containing multiple messages or nested bundles.
|
|
18
|
+
*
|
|
19
|
+
* OSC bundles allow multiple messages to be sent together, optionally with
|
|
20
|
+
* a timetag indicating when the bundle should be processed.
|
|
21
|
+
*
|
|
22
|
+
* @class
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Create a bundle without a timetag
|
|
26
|
+
* const bundle = new Bundle(['/one', 1], ['/two', 2]);
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Create a bundle with a timetag
|
|
30
|
+
* const bundle = new Bundle(10, ['/one', 1], ['/two', 2]);
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Nest bundles
|
|
34
|
+
* const bundle1 = new Bundle(['/one', 1]);
|
|
35
|
+
* const bundle2 = new Bundle(['/two', 2]);
|
|
36
|
+
* bundle1.append(bundle2);
|
|
37
|
+
*/
|
|
10
38
|
class Bundle {
|
|
39
|
+
/**
|
|
40
|
+
* Create an OSC Bundle.
|
|
41
|
+
*
|
|
42
|
+
* @param {number|Message|Bundle|Array} [timetagOrElement=0] - Timetag, or if not a number, the first element and timetag will default to 0.
|
|
43
|
+
* @param {...(Message|Bundle|Array)} elements - Messages or bundles to include.
|
|
44
|
+
* Arrays will be automatically converted to Message objects.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // Bundle without timetag
|
|
48
|
+
* const bundle = new Bundle(['/test', 1], ['/test2', 2]);
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* // Bundle with timetag of 10
|
|
52
|
+
* const bundle = new Bundle(10, ['/test', 1]);
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // Bundle with Message objects
|
|
56
|
+
* const msg1 = new Message('/one', 1);
|
|
57
|
+
* const msg2 = new Message('/two', 2);
|
|
58
|
+
* const bundle = new Bundle(msg1, msg2);
|
|
59
|
+
*/
|
|
11
60
|
constructor(timetag, ...elements) {
|
|
12
61
|
if (!(typeof timetag === 'number')) {
|
|
13
62
|
elements.unshift(timetag);
|
|
@@ -18,6 +67,23 @@ class Bundle {
|
|
|
18
67
|
this.elements = elements.map(sanitize);
|
|
19
68
|
}
|
|
20
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Append a message or bundle to this bundle.
|
|
72
|
+
*
|
|
73
|
+
* @param {Message|Bundle|Array} element - The message or bundle to append.
|
|
74
|
+
* Arrays will be automatically converted to Message objects.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* const bundle = new Bundle();
|
|
78
|
+
* bundle.append(['/test', 1]);
|
|
79
|
+
* bundle.append(new Message('/test2', 2));
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* // Append a nested bundle
|
|
83
|
+
* const bundle1 = new Bundle(['/one', 1]);
|
|
84
|
+
* const bundle2 = new Bundle(['/two', 2]);
|
|
85
|
+
* bundle1.append(bundle2);
|
|
86
|
+
*/
|
|
21
87
|
append(element) {
|
|
22
88
|
this.elements.push(sanitize(element));
|
|
23
89
|
}
|
package/dist/lib/Client.js
CHANGED
|
@@ -1,44 +1,94 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var node_dgram = require('node:dgram');
|
|
4
|
-
var
|
|
4
|
+
var node_events = require('node:events');
|
|
5
|
+
var osc = require('./osc.js');
|
|
5
6
|
var Message = require('./Message.js');
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* OSC Client for sending messages and bundles over UDP.
|
|
10
|
+
*
|
|
11
|
+
* Extends EventEmitter and emits the following events:
|
|
12
|
+
* - 'error': Emitted when a socket error occurs
|
|
13
|
+
*
|
|
14
|
+
* @class
|
|
15
|
+
* @extends EventEmitter
|
|
16
|
+
* @example
|
|
17
|
+
* // Create a client
|
|
18
|
+
* const client = new Client('127.0.0.1', 3333);
|
|
19
|
+
*
|
|
20
|
+
* // Send a message with callback
|
|
21
|
+
* client.send('/oscAddress', 200, (err) => {
|
|
22
|
+
* if (err) console.error(err);
|
|
23
|
+
* client.close();
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Send a message with async/await
|
|
28
|
+
* const client = new Client('127.0.0.1', 3333);
|
|
29
|
+
* await client.send('/oscAddress', 200);
|
|
30
|
+
* await client.close();
|
|
31
|
+
*/
|
|
32
|
+
class Client extends node_events.EventEmitter {
|
|
33
|
+
/**
|
|
34
|
+
* Create an OSC Client.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} host - The hostname or IP address of the OSC server.
|
|
37
|
+
* @param {number} port - The port number of the OSC server.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const client = new Client('127.0.0.1', 3333);
|
|
41
|
+
*/
|
|
8
42
|
constructor(host, port) {
|
|
43
|
+
super();
|
|
9
44
|
this.host = host;
|
|
10
45
|
this.port = port;
|
|
11
46
|
this._sock = node_dgram.createSocket({
|
|
12
47
|
type: 'udp4',
|
|
13
48
|
reuseAddr: true
|
|
14
49
|
});
|
|
50
|
+
|
|
51
|
+
this._sock.on('error', (err) => {
|
|
52
|
+
this.emit('error', err);
|
|
53
|
+
});
|
|
15
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Close the client socket.
|
|
57
|
+
*
|
|
58
|
+
* This method can be used with either a callback or as a Promise.
|
|
59
|
+
*
|
|
60
|
+
* @param {Function} [cb] - Optional callback function called when socket is closed.
|
|
61
|
+
* @returns {Promise<void>|undefined} Returns a Promise if no callback is provided.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // With callback
|
|
65
|
+
* client.close((err) => {
|
|
66
|
+
* if (err) console.error(err);
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* // With async/await
|
|
71
|
+
* await client.close();
|
|
72
|
+
*/
|
|
16
73
|
close(cb) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
callback = () => {};
|
|
74
|
+
if (cb) {
|
|
75
|
+
this._sock.close(cb);
|
|
76
|
+
} else {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
this._sock.close((err) => {
|
|
79
|
+
if (err) reject(err);
|
|
80
|
+
else resolve();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
27
83
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
message = {
|
|
31
|
-
address: message[0],
|
|
32
|
-
args: message.splice(1)
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
84
|
+
}
|
|
85
|
+
_performSend(message, args, callback) {
|
|
36
86
|
let mes;
|
|
37
87
|
let buf;
|
|
38
88
|
try {
|
|
39
89
|
switch (typeof message) {
|
|
40
90
|
case 'object':
|
|
41
|
-
buf =
|
|
91
|
+
buf = osc.encode(message);
|
|
42
92
|
this._sock.send(buf, 0, buf.length, this.port, this.host, callback);
|
|
43
93
|
break;
|
|
44
94
|
case 'string':
|
|
@@ -46,7 +96,7 @@ class Client {
|
|
|
46
96
|
for (let i = 1; i < args.length; i++) {
|
|
47
97
|
mes.append(args[i]);
|
|
48
98
|
}
|
|
49
|
-
buf =
|
|
99
|
+
buf = osc.encode(mes);
|
|
50
100
|
this._sock.send(buf, 0, buf.length, this.port, this.host, callback);
|
|
51
101
|
break;
|
|
52
102
|
default:
|
|
@@ -60,6 +110,71 @@ class Client {
|
|
|
60
110
|
callback(error);
|
|
61
111
|
}
|
|
62
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Send an OSC message or bundle to the server.
|
|
115
|
+
*
|
|
116
|
+
* This method can be used with either a callback or as a Promise.
|
|
117
|
+
* Messages can be sent in several formats:
|
|
118
|
+
* - As separate arguments: address followed by values
|
|
119
|
+
* - As a Message or Bundle object
|
|
120
|
+
* - As an array: [address, ...values]
|
|
121
|
+
*
|
|
122
|
+
* @param {...*} args - The message to send. Can be:
|
|
123
|
+
* - (address: string, ...values: any[], callback?: Function)
|
|
124
|
+
* - (message: Message|Bundle, callback?: Function)
|
|
125
|
+
* - (array: Array, callback?: Function)
|
|
126
|
+
* @returns {Promise<void>|undefined} Returns a Promise if no callback is provided.
|
|
127
|
+
*
|
|
128
|
+
* @throws {TypeError} If the message format is invalid.
|
|
129
|
+
* @throws {ReferenceError} If attempting to send on a closed socket.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* // Send with address and arguments
|
|
133
|
+
* client.send('/oscAddress', 200, 'hello', (err) => {
|
|
134
|
+
* if (err) console.error(err);
|
|
135
|
+
* });
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* // Send with async/await
|
|
139
|
+
* await client.send('/oscAddress', 200, 'hello');
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* // Send a Message object
|
|
143
|
+
* const msg = new Message('/test', 1, 2, 3);
|
|
144
|
+
* await client.send(msg);
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* // Send a Bundle object
|
|
148
|
+
* const bundle = new Bundle(['/one', 1], ['/two', 2]);
|
|
149
|
+
* await client.send(bundle);
|
|
150
|
+
*/
|
|
151
|
+
send(...args) {
|
|
152
|
+
let message = args[0];
|
|
153
|
+
let callback;
|
|
154
|
+
|
|
155
|
+
// Convert array syntax to message object
|
|
156
|
+
if (message instanceof Array) {
|
|
157
|
+
message = {
|
|
158
|
+
address: message[0],
|
|
159
|
+
args: message.splice(1)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (typeof args[args.length - 1] === 'function') {
|
|
164
|
+
callback = args.pop();
|
|
165
|
+
this._performSend(message, args, callback);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// No callback provided, return a Promise
|
|
169
|
+
return new Promise((resolve, reject) => {
|
|
170
|
+
callback = (err) => {
|
|
171
|
+
if (err) reject(err);
|
|
172
|
+
else resolve();
|
|
173
|
+
};
|
|
174
|
+
this._performSend(message, args, callback);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
63
178
|
}
|
|
64
179
|
|
|
65
180
|
module.exports = Client;
|
package/dist/lib/Message.js
CHANGED
|
@@ -4,23 +4,109 @@ const typeTags = {
|
|
|
4
4
|
s: 'string',
|
|
5
5
|
f: 'float',
|
|
6
6
|
i: 'integer',
|
|
7
|
-
b: 'blob'
|
|
7
|
+
b: 'blob',
|
|
8
|
+
m: 'midi'
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Represents a typed argument for an OSC message.
|
|
13
|
+
*
|
|
14
|
+
* @class
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
10
17
|
class Argument {
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} type - The type of the argument (string, float, integer, blob, boolean).
|
|
20
|
+
* @param {*} value - The value of the argument.
|
|
21
|
+
*/
|
|
11
22
|
constructor(type, value) {
|
|
12
23
|
this.type = type;
|
|
13
24
|
this.value = value;
|
|
14
25
|
}
|
|
15
26
|
}
|
|
16
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Represents an OSC message with an address and arguments.
|
|
30
|
+
*
|
|
31
|
+
* OSC messages consist of an address pattern (string starting with '/')
|
|
32
|
+
* and zero or more arguments of various types.
|
|
33
|
+
*
|
|
34
|
+
* @class
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // Create a message with constructor arguments
|
|
38
|
+
* const msg = new Message('/test', 1, 2, 'hello');
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Create a message and append arguments
|
|
42
|
+
* const msg = new Message('/test');
|
|
43
|
+
* msg.append(1);
|
|
44
|
+
* msg.append('hello');
|
|
45
|
+
* msg.append(3.14);
|
|
46
|
+
*/
|
|
17
47
|
class Message {
|
|
48
|
+
/**
|
|
49
|
+
* Create an OSC Message.
|
|
50
|
+
*
|
|
51
|
+
* @param {string} address - The OSC address pattern (e.g., '/oscillator/frequency').
|
|
52
|
+
* @param {...*} args - Optional arguments to include in the message.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const msg = new Message('/test');
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const msg = new Message('/test', 1, 2, 3);
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const msg = new Message('/synth', 'note', 60, 0.5);
|
|
62
|
+
*/
|
|
18
63
|
constructor(address, ...args) {
|
|
19
64
|
this.oscType = 'message';
|
|
20
65
|
this.address = address;
|
|
21
66
|
this.args = args;
|
|
22
67
|
}
|
|
23
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Append an argument to the message.
|
|
71
|
+
*
|
|
72
|
+
* Automatically detects the type based on the JavaScript type:
|
|
73
|
+
* - Integers are encoded as OSC integers
|
|
74
|
+
* - Floats are encoded as OSC floats
|
|
75
|
+
* - Strings are encoded as OSC strings
|
|
76
|
+
* - Booleans are encoded as OSC booleans
|
|
77
|
+
* - Buffers are encoded as OSC blobs
|
|
78
|
+
* - Arrays are recursively appended
|
|
79
|
+
* - Objects with a 'type' property are used as-is
|
|
80
|
+
*
|
|
81
|
+
* @param {*} arg - The argument to append. Can be:
|
|
82
|
+
* - A primitive value (number, string, boolean)
|
|
83
|
+
* - A Buffer (encoded as blob)
|
|
84
|
+
* - An array of values (will be recursively appended)
|
|
85
|
+
* - An object with 'type' and 'value' properties for explicit type control
|
|
86
|
+
*
|
|
87
|
+
* @throws {Error} If the argument type cannot be encoded.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const msg = new Message('/test');
|
|
91
|
+
* msg.append(42); // Integer
|
|
92
|
+
* msg.append(3.14); // Float
|
|
93
|
+
* msg.append('hello'); // String
|
|
94
|
+
* msg.append(true); // Boolean
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* // Append multiple values at once
|
|
98
|
+
* msg.append([1, 2, 3]);
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // Explicitly specify type
|
|
102
|
+
* msg.append({ type: 'float', value: 42 });
|
|
103
|
+
* msg.append({ type: 'blob', value: Buffer.from('data') });
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* // MIDI messages (4 bytes: port, status, data1, data2)
|
|
107
|
+
* msg.append({ type: 'midi', value: { port: 0, status: 144, data1: 60, data2: 127 } });
|
|
108
|
+
* msg.append({ type: 'm', value: Buffer.from([0, 144, 60, 127]) });
|
|
109
|
+
*/
|
|
24
110
|
append(arg) {
|
|
25
111
|
let argOut;
|
|
26
112
|
switch (typeof arg) {
|