node-osc 11.2.1 → 11.2.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.
- package/.github/workflows/nodejs.yml +1 -1
- package/README.md +3 -2
- package/agent.md +330 -0
- package/dist/lib/Server.js +7 -12
- package/dist/lib/internal/decode.js +3 -1
- package/dist/lib/osc.js +29 -1
- package/dist/test/lib/osc.js +29 -1
- package/dist/test/test-bundle.js +13 -12
- package/dist/test/test-client.js +49 -40
- package/dist/test/test-decode.js +35 -0
- package/dist/test/test-e2e.js +9 -9
- package/dist/test/test-encode-decode.js +96 -0
- package/dist/test/test-error-handling.js +14 -13
- package/dist/test/test-message.js +169 -119
- package/dist/test/test-osc-internal.js +151 -0
- package/dist/test/test-promises.js +71 -29
- package/dist/test/test-server.js +19 -16
- package/docs/README.md +81 -0
- package/examples/README.md +3 -1
- package/lib/Server.mjs +7 -12
- package/lib/internal/decode.mjs +3 -1
- package/lib/osc.mjs +29 -1
- package/package.json +2 -2
- package/test/test-bundle.mjs +14 -13
- package/test/test-client.mjs +50 -41
- package/test/test-decode.mjs +35 -0
- package/test/test-e2e.mjs +10 -10
- package/test/test-encode-decode.mjs +96 -0
- package/test/test-error-handling.mjs +15 -14
- package/test/test-message.mjs +171 -122
- package/test/test-osc-internal.mjs +151 -0
- package/test/test-promises.mjs +72 -30
- package/test/test-server.mjs +20 -17
- package/types/Server.d.mts.map +1 -1
- package/types/internal/decode.d.mts.map +1 -1
- package/types/osc.d.mts.map +1 -1
- package/dist/test/test-getPort.js +0 -20
- package/dist/test/util.js +0 -34
- package/test/test-getPort.mjs +0 -18
- package/test/util.mjs +0 -34
|
@@ -2,19 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
var node_events = require('node:events');
|
|
4
4
|
var tap = require('tap');
|
|
5
|
-
var util = require('./util.js');
|
|
6
5
|
var nodeOsc = require('node-osc');
|
|
7
6
|
|
|
8
|
-
tap.beforeEach(util.bootstrap);
|
|
9
|
-
|
|
10
7
|
tap.test('client: send with promise - array', async (t) => {
|
|
11
|
-
const
|
|
12
|
-
|
|
8
|
+
const server = new nodeOsc.Server(0, '127.0.0.1');
|
|
9
|
+
await node_events.once(server, 'listening');
|
|
10
|
+
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
|
13
11
|
|
|
14
12
|
t.plan(1);
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
server.on('message', (msg) => {
|
|
15
|
+
server.close();
|
|
18
16
|
t.same(msg, ['/test', 0, 1, 'testing', true], 'We should receive expected payload');
|
|
19
17
|
});
|
|
20
18
|
|
|
@@ -23,8 +21,9 @@ tap.test('client: send with promise - array', async (t) => {
|
|
|
23
21
|
});
|
|
24
22
|
|
|
25
23
|
tap.test('client: array is not mutated when sent with promise', async (t) => {
|
|
26
|
-
const oscServer = new nodeOsc.Server(
|
|
27
|
-
|
|
24
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
25
|
+
await node_events.once(oscServer, 'listening');
|
|
26
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
28
27
|
|
|
29
28
|
t.plan(2);
|
|
30
29
|
|
|
@@ -45,8 +44,9 @@ tap.test('client: array is not mutated when sent with promise', async (t) => {
|
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
tap.test('client: send with promise - string', async (t) => {
|
|
48
|
-
const oscServer = new nodeOsc.Server(
|
|
49
|
-
|
|
47
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
48
|
+
await node_events.once(oscServer, 'listening');
|
|
49
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
50
50
|
|
|
51
51
|
t.plan(1);
|
|
52
52
|
|
|
@@ -60,8 +60,9 @@ tap.test('client: send with promise - string', async (t) => {
|
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
tap.test('client: send with promise - message object', async (t) => {
|
|
63
|
-
const oscServer = new nodeOsc.Server(
|
|
64
|
-
|
|
63
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
64
|
+
await node_events.once(oscServer, 'listening');
|
|
65
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
65
66
|
|
|
66
67
|
t.plan(1);
|
|
67
68
|
|
|
@@ -78,8 +79,9 @@ tap.test('client: send with promise - message object', async (t) => {
|
|
|
78
79
|
});
|
|
79
80
|
|
|
80
81
|
tap.test('client: send with promise - multiple args', async (t) => {
|
|
81
|
-
const oscServer = new nodeOsc.Server(
|
|
82
|
-
|
|
82
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
83
|
+
await node_events.once(oscServer, 'listening');
|
|
84
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
83
85
|
|
|
84
86
|
t.plan(1);
|
|
85
87
|
|
|
@@ -93,12 +95,15 @@ tap.test('client: send with promise - multiple args', async (t) => {
|
|
|
93
95
|
});
|
|
94
96
|
|
|
95
97
|
tap.test('client: send promise rejection on closed socket', async (t) => {
|
|
96
|
-
const
|
|
98
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
99
|
+
await node_events.once(oscServer, 'listening');
|
|
100
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
97
101
|
|
|
98
102
|
t.plan(1);
|
|
99
103
|
|
|
100
104
|
await client.close();
|
|
101
|
-
|
|
105
|
+
await oscServer.close();
|
|
106
|
+
|
|
102
107
|
try {
|
|
103
108
|
await client.send('/boom');
|
|
104
109
|
t.fail('Should have thrown an error');
|
|
@@ -108,8 +113,9 @@ tap.test('client: send promise rejection on closed socket', async (t) => {
|
|
|
108
113
|
});
|
|
109
114
|
|
|
110
115
|
tap.test('client: async/await usage', async (t) => {
|
|
111
|
-
const oscServer = new nodeOsc.Server(
|
|
112
|
-
|
|
116
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
117
|
+
await node_events.once(oscServer, 'listening');
|
|
118
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
113
119
|
|
|
114
120
|
t.plan(1);
|
|
115
121
|
|
|
@@ -125,7 +131,7 @@ tap.test('client: async/await usage', async (t) => {
|
|
|
125
131
|
});
|
|
126
132
|
|
|
127
133
|
tap.test('server: close with promise', async (t) => {
|
|
128
|
-
const oscServer = new nodeOsc.Server(
|
|
134
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
129
135
|
|
|
130
136
|
t.plan(1);
|
|
131
137
|
|
|
@@ -136,7 +142,7 @@ tap.test('server: close with promise', async (t) => {
|
|
|
136
142
|
});
|
|
137
143
|
|
|
138
144
|
tap.test('server: no callback still emits listening event', async (t) => {
|
|
139
|
-
const oscServer = new nodeOsc.Server(
|
|
145
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
140
146
|
|
|
141
147
|
t.plan(1);
|
|
142
148
|
|
|
@@ -147,15 +153,16 @@ tap.test('server: no callback still emits listening event', async (t) => {
|
|
|
147
153
|
});
|
|
148
154
|
|
|
149
155
|
tap.test('client and server: full async/await workflow', async (t) => {
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
t.plan(2);
|
|
156
|
+
t.plan(3);
|
|
157
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
154
158
|
|
|
155
159
|
// Wait for server to be ready
|
|
156
160
|
await node_events.once(oscServer, 'listening');
|
|
157
161
|
t.pass('Server started');
|
|
158
162
|
|
|
163
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
164
|
+
t.pass('Client created');
|
|
165
|
+
|
|
159
166
|
// Set up message handler
|
|
160
167
|
const messageReceived = node_events.once(oscServer, 'message');
|
|
161
168
|
|
|
@@ -170,9 +177,9 @@ tap.test('client and server: full async/await workflow', async (t) => {
|
|
|
170
177
|
});
|
|
171
178
|
|
|
172
179
|
tap.test('client: multiple sends with promises', async (t) => {
|
|
173
|
-
const oscServer = new nodeOsc.Server(
|
|
174
|
-
|
|
175
|
-
|
|
180
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
181
|
+
await node_events.once(oscServer, 'listening');
|
|
182
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
176
183
|
t.plan(3);
|
|
177
184
|
|
|
178
185
|
const messages = [];
|
|
@@ -196,6 +203,8 @@ tap.test('client: multiple sends with promises', async (t) => {
|
|
|
196
203
|
});
|
|
197
204
|
|
|
198
205
|
tap.test('client: close promise rejection on error', async (t) => {
|
|
206
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
207
|
+
await node_events.once(oscServer, 'listening');
|
|
199
208
|
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
|
200
209
|
|
|
201
210
|
t.plan(1);
|
|
@@ -225,6 +234,7 @@ tap.test('client: close promise rejection on error', async (t) => {
|
|
|
225
234
|
};
|
|
226
235
|
|
|
227
236
|
try {
|
|
237
|
+
await oscServer.close();
|
|
228
238
|
await client.close();
|
|
229
239
|
t.fail('Should have thrown an error');
|
|
230
240
|
} catch (err) {
|
|
@@ -233,7 +243,7 @@ tap.test('client: close promise rejection on error', async (t) => {
|
|
|
233
243
|
});
|
|
234
244
|
|
|
235
245
|
tap.test('server: close promise rejection on error', async (t) => {
|
|
236
|
-
const oscServer = new nodeOsc.Server(
|
|
246
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
237
247
|
|
|
238
248
|
t.plan(1);
|
|
239
249
|
|
|
@@ -270,3 +280,35 @@ tap.test('server: close promise rejection on error', async (t) => {
|
|
|
270
280
|
t.equal(err.code, 'MOCK_ERROR', 'Should reject with mock error');
|
|
271
281
|
}
|
|
272
282
|
});
|
|
283
|
+
|
|
284
|
+
tap.test('client: send promise rejection on send error', async (t) => {
|
|
285
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
286
|
+
await node_events.once(oscServer, 'listening');
|
|
287
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
288
|
+
|
|
289
|
+
t.plan(1);
|
|
290
|
+
|
|
291
|
+
// Mock the socket's send method to simulate an error
|
|
292
|
+
const originalSend = client._sock.send;
|
|
293
|
+
client._sock.send = function(msg, offset, length, port, address, callback) {
|
|
294
|
+
// Simulate an error being passed to callback
|
|
295
|
+
const err = new Error('Mock send error');
|
|
296
|
+
err.code = 'MOCK_SEND_ERROR';
|
|
297
|
+
if (callback) {
|
|
298
|
+
setImmediate(() => callback(err));
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
t.teardown(async () => {
|
|
303
|
+
client._sock.send = originalSend;
|
|
304
|
+
await client.close();
|
|
305
|
+
await oscServer.close();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
await client.send('/test', 'data');
|
|
310
|
+
t.fail('Should have thrown an error');
|
|
311
|
+
} catch (err) {
|
|
312
|
+
t.equal(err.code, 'MOCK_SEND_ERROR', 'Should reject with mock send error');
|
|
313
|
+
}
|
|
314
|
+
});
|
package/dist/test/test-server.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var node_events = require('node:events');
|
|
3
4
|
var tap = require('tap');
|
|
4
|
-
var util = require('./util.js');
|
|
5
5
|
var nodeOsc = require('node-osc');
|
|
6
6
|
|
|
7
|
-
tap.
|
|
8
|
-
|
|
9
|
-
tap.test('server: create and close', (t) => {
|
|
7
|
+
tap.test('server: create and close', async (t) => {
|
|
10
8
|
t.plan(1);
|
|
11
|
-
const oscServer = new nodeOsc.Server(
|
|
9
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
10
|
+
await node_events.once(oscServer, 'listening');
|
|
12
11
|
oscServer.close((err) => {
|
|
13
12
|
t.error(err);
|
|
14
13
|
});
|
|
15
14
|
});
|
|
16
15
|
|
|
17
|
-
tap.test('server: listen to message', (t) => {
|
|
18
|
-
const oscServer = new nodeOsc.Server(
|
|
19
|
-
|
|
16
|
+
tap.test('server: listen to message', async (t) => {
|
|
17
|
+
const oscServer = new nodeOsc.Server(0);
|
|
18
|
+
await node_events.once(oscServer, 'listening');
|
|
19
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
20
20
|
|
|
21
21
|
t.plan(3);
|
|
22
22
|
|
|
@@ -38,9 +38,10 @@ tap.test('server: listen to message', (t) => {
|
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
tap.test('server: no defined host', (t) => {
|
|
42
|
-
const oscServer = new nodeOsc.Server(
|
|
43
|
-
|
|
41
|
+
tap.test('server: no defined host', async (t) => {
|
|
42
|
+
const oscServer = new nodeOsc.Server(0);
|
|
43
|
+
await node_events.once(oscServer, 'listening');
|
|
44
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
44
45
|
|
|
45
46
|
t.plan(3);
|
|
46
47
|
|
|
@@ -62,12 +63,13 @@ tap.test('server: no defined host', (t) => {
|
|
|
62
63
|
});
|
|
63
64
|
});
|
|
64
65
|
|
|
65
|
-
tap.test('server: callback as second arg', (t) => {
|
|
66
|
+
tap.test('server: callback as second arg', async (t) => {
|
|
66
67
|
t.plan(4);
|
|
67
|
-
const oscServer = new nodeOsc.Server(
|
|
68
|
+
const oscServer = new nodeOsc.Server(0, () => {
|
|
68
69
|
t.ok('callback called');
|
|
69
70
|
});
|
|
70
|
-
|
|
71
|
+
await node_events.once(oscServer, 'listening');
|
|
72
|
+
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
|
71
73
|
|
|
72
74
|
t.teardown(() => {
|
|
73
75
|
oscServer.close();
|
|
@@ -87,9 +89,10 @@ tap.test('server: callback as second arg', (t) => {
|
|
|
87
89
|
});
|
|
88
90
|
});
|
|
89
91
|
|
|
90
|
-
tap.test('server: bad message', (t) => {
|
|
92
|
+
tap.test('server: bad message', async (t) => {
|
|
91
93
|
t.plan(2);
|
|
92
|
-
const oscServer = new nodeOsc.Server(
|
|
94
|
+
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
|
95
|
+
await node_events.once(oscServer, 'listening');
|
|
93
96
|
t.throws(() => {
|
|
94
97
|
oscServer._sock.emit('message', 'whoops');
|
|
95
98
|
}, /can't decode incoming message:/);
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# node-osc Documentation
|
|
2
|
+
|
|
3
|
+
Welcome to the node-osc documentation! This directory contains comprehensive documentation for the node-osc library.
|
|
4
|
+
|
|
5
|
+
## Documentation Overview
|
|
6
|
+
|
|
7
|
+
### 📚 [API Reference](./API.md)
|
|
8
|
+
**Complete API documentation for all classes and functions**
|
|
9
|
+
|
|
10
|
+
Auto-generated from JSDoc comments in the source code. This is your reference for:
|
|
11
|
+
- All classes: `Server`, `Client`, `Message`, `Bundle`
|
|
12
|
+
- All methods and their parameters
|
|
13
|
+
- Low-level functions: `encode()` and `decode()`
|
|
14
|
+
- Return types and error conditions
|
|
15
|
+
- Code examples for each API
|
|
16
|
+
|
|
17
|
+
> **Note:** This file is automatically generated. To update it, edit the JSDoc comments in the source code and run `npm run docs`.
|
|
18
|
+
|
|
19
|
+
### 📘 [Usage Guide](./GUIDE.md)
|
|
20
|
+
**Best practices, patterns, and troubleshooting**
|
|
21
|
+
|
|
22
|
+
A comprehensive guide covering:
|
|
23
|
+
- Event handling patterns
|
|
24
|
+
- Error handling strategies
|
|
25
|
+
- OSC type system details
|
|
26
|
+
- Best practices for production use
|
|
27
|
+
- Troubleshooting common issues
|
|
28
|
+
- Advanced topics like custom transports and performance optimization
|
|
29
|
+
|
|
30
|
+
## Quick Navigation
|
|
31
|
+
|
|
32
|
+
**New to node-osc?**
|
|
33
|
+
1. Start with the [main README](../README.md) for a quick introduction and installation
|
|
34
|
+
2. Try the [examples](../examples/) to see working code
|
|
35
|
+
3. Read the [Usage Guide](./GUIDE.md) to learn best practices
|
|
36
|
+
4. Reference the [API documentation](./API.md) as needed
|
|
37
|
+
|
|
38
|
+
**Looking for something specific?**
|
|
39
|
+
- **How to send/receive messages** → [API Reference](./API.md) (Server and Client sections)
|
|
40
|
+
- **How to handle errors** → [Usage Guide](./GUIDE.md#error-handling)
|
|
41
|
+
- **Type system and data types** → [Usage Guide](./GUIDE.md#type-system)
|
|
42
|
+
- **Working with bundles** → [API Reference](./API.md#bundle)
|
|
43
|
+
- **Troubleshooting** → [Usage Guide](./GUIDE.md#troubleshooting)
|
|
44
|
+
- **Code examples** → [Examples directory](../examples/)
|
|
45
|
+
- **Advanced use cases** → [Usage Guide](./GUIDE.md#advanced-topics)
|
|
46
|
+
|
|
47
|
+
## Additional Resources
|
|
48
|
+
|
|
49
|
+
- **[Examples](../examples/)** - Working code examples for various use cases
|
|
50
|
+
- **[Main README](../README.md)** - Quick start and project overview
|
|
51
|
+
- **[OSC Specification](http://opensoundcontrol.org/spec-1_0)** - Official OSC protocol documentation
|
|
52
|
+
|
|
53
|
+
## Contributing to Documentation
|
|
54
|
+
|
|
55
|
+
### Updating API Documentation
|
|
56
|
+
|
|
57
|
+
The API documentation is automatically generated from JSDoc comments:
|
|
58
|
+
|
|
59
|
+
1. Edit JSDoc comments in the source files (`lib/**/*.mjs`)
|
|
60
|
+
2. Run `npm run docs` to regenerate `API.md`
|
|
61
|
+
3. Review the changes and commit
|
|
62
|
+
|
|
63
|
+
### Updating the Usage Guide
|
|
64
|
+
|
|
65
|
+
The Usage Guide (`GUIDE.md`) is manually maintained. When editing:
|
|
66
|
+
|
|
67
|
+
- Keep it focused on patterns, best practices, and how-to content
|
|
68
|
+
- Avoid duplicating API details (link to API.md instead)
|
|
69
|
+
- Include practical code examples
|
|
70
|
+
- Update the table of contents if adding new sections
|
|
71
|
+
|
|
72
|
+
## Documentation Structure Philosophy
|
|
73
|
+
|
|
74
|
+
Our documentation is organized to minimize duplication while maximizing usefulness:
|
|
75
|
+
|
|
76
|
+
- **README.md** (main) → Quick start, basic examples, installation
|
|
77
|
+
- **API.md** → Complete API reference with all technical details
|
|
78
|
+
- **GUIDE.md** → How to use the library effectively, patterns, and troubleshooting
|
|
79
|
+
- **examples/** → Working code you can run and learn from
|
|
80
|
+
|
|
81
|
+
This structure ensures you can find what you need without reading through repeated content.
|
package/examples/README.md
CHANGED
|
@@ -115,5 +115,7 @@ Demonstrates:
|
|
|
115
115
|
## Further Reading
|
|
116
116
|
|
|
117
117
|
- [Main README](../README.md) - Quick start guide
|
|
118
|
-
- [
|
|
118
|
+
- [Documentation Hub](../docs/) - Complete documentation with navigation guide
|
|
119
|
+
- [API Reference](../docs/API.md) - Complete API reference
|
|
120
|
+
- [Usage Guide](../docs/GUIDE.md) - Best practices and troubleshooting
|
|
119
121
|
- [OSC Specification](http://opensoundcontrol.org/spec-1_0) - Learn about the OSC protocol
|
package/lib/Server.mjs
CHANGED
|
@@ -90,18 +90,13 @@ class Server extends EventEmitter {
|
|
|
90
90
|
});
|
|
91
91
|
this._sock.bind(port, host);
|
|
92
92
|
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
// For promise support, still emit the event but don't require a callback
|
|
101
|
-
this._sock.on('listening', () => {
|
|
102
|
-
this.emit('listening');
|
|
103
|
-
});
|
|
104
|
-
}
|
|
93
|
+
// Update port and emit listening event when socket is ready
|
|
94
|
+
this._sock.on('listening', () => {
|
|
95
|
+
// Update port with actual bound port (important when using port 0)
|
|
96
|
+
this.port = this._sock.address().port;
|
|
97
|
+
this.emit('listening');
|
|
98
|
+
if (cb) cb();
|
|
99
|
+
});
|
|
105
100
|
|
|
106
101
|
this._sock.on('message', (msg, rinfo) => {
|
|
107
102
|
try {
|
package/lib/internal/decode.mjs
CHANGED
|
@@ -3,7 +3,8 @@ import { decode } from '../osc.mjs';
|
|
|
3
3
|
function sanitizeMessage(decoded) {
|
|
4
4
|
const message = [];
|
|
5
5
|
message.push(decoded.address);
|
|
6
|
-
decoded.args
|
|
6
|
+
const args = decoded.args ?? [];
|
|
7
|
+
args.forEach(arg => {
|
|
7
8
|
message.push(arg.value);
|
|
8
9
|
});
|
|
9
10
|
return message;
|
|
@@ -13,6 +14,7 @@ function sanitizeBundle(decoded) {
|
|
|
13
14
|
decoded.elements = decoded.elements.map(element => {
|
|
14
15
|
if (element.oscType === 'bundle') return sanitizeBundle(element);
|
|
15
16
|
else if (element.oscType === 'message') return sanitizeMessage(element);
|
|
17
|
+
throw new Error('Malformed Packet');
|
|
16
18
|
});
|
|
17
19
|
return decoded;
|
|
18
20
|
}
|
package/lib/osc.mjs
CHANGED
|
@@ -17,6 +17,9 @@ function readString(buffer, offset) {
|
|
|
17
17
|
while (end < buffer.length && buffer[end] !== 0) {
|
|
18
18
|
end++;
|
|
19
19
|
}
|
|
20
|
+
if (end >= buffer.length) {
|
|
21
|
+
throw new Error('Malformed Packet: Missing null terminator for string');
|
|
22
|
+
}
|
|
20
23
|
const str = buffer.subarray(offset, end).toString('utf8');
|
|
21
24
|
// Find next 4-byte boundary
|
|
22
25
|
const paddedLength = Math.ceil((end - offset + 1) / 4) * 4;
|
|
@@ -30,6 +33,9 @@ function writeInt32(value) {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
function readInt32(buffer, offset) {
|
|
36
|
+
if (offset + 4 > buffer.length) {
|
|
37
|
+
throw new Error('Malformed Packet: Not enough bytes for int32');
|
|
38
|
+
}
|
|
33
39
|
const value = buffer.readInt32BE(offset);
|
|
34
40
|
return { value, offset: offset + 4 };
|
|
35
41
|
}
|
|
@@ -41,6 +47,9 @@ function writeFloat32(value) {
|
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
function readFloat32(buffer, offset) {
|
|
50
|
+
if (offset + 4 > buffer.length) {
|
|
51
|
+
throw new Error('Malformed Packet: Not enough bytes for float32');
|
|
52
|
+
}
|
|
44
53
|
const value = buffer.readFloatBE(offset);
|
|
45
54
|
return { value, offset: offset + 4 };
|
|
46
55
|
}
|
|
@@ -56,9 +65,18 @@ function writeBlob(value) {
|
|
|
56
65
|
function readBlob(buffer, offset) {
|
|
57
66
|
const lengthResult = readInt32(buffer, offset);
|
|
58
67
|
const length = lengthResult.value;
|
|
68
|
+
if (length < 0) {
|
|
69
|
+
throw new Error('Malformed Packet: Invalid blob length');
|
|
70
|
+
}
|
|
71
|
+
if (lengthResult.offset + length > buffer.length) {
|
|
72
|
+
throw new Error('Malformed Packet: Not enough bytes for blob');
|
|
73
|
+
}
|
|
59
74
|
const data = buffer.subarray(lengthResult.offset, lengthResult.offset + length);
|
|
60
75
|
const padding = 4 - (length % 4);
|
|
61
76
|
const nextOffset = lengthResult.offset + length + (padding === 4 ? 0 : padding);
|
|
77
|
+
if (nextOffset > buffer.length) {
|
|
78
|
+
throw new Error('Malformed Packet: Not enough bytes for blob padding');
|
|
79
|
+
}
|
|
62
80
|
return { value: data, offset: nextOffset };
|
|
63
81
|
}
|
|
64
82
|
|
|
@@ -66,7 +84,11 @@ function writeTimeTag(value) {
|
|
|
66
84
|
// For now, treat timetag as a double (8 bytes)
|
|
67
85
|
// OSC timetag is 64-bit: 32-bit seconds since 1900, 32-bit fractional
|
|
68
86
|
const buffer = Buffer.alloc(8);
|
|
69
|
-
if (
|
|
87
|
+
if (value === 0 || value === null || value === undefined) {
|
|
88
|
+
// Immediate execution
|
|
89
|
+
buffer.writeUInt32BE(0, 0);
|
|
90
|
+
buffer.writeUInt32BE(1, 4);
|
|
91
|
+
} else if (typeof value === 'number') {
|
|
70
92
|
// Convert to OSC timetag format
|
|
71
93
|
const seconds = Math.floor(value);
|
|
72
94
|
const fraction = Math.floor((value - seconds) * 0x100000000);
|
|
@@ -81,6 +103,9 @@ function writeTimeTag(value) {
|
|
|
81
103
|
}
|
|
82
104
|
|
|
83
105
|
function readTimeTag(buffer, offset) {
|
|
106
|
+
if (offset + 8 > buffer.length) {
|
|
107
|
+
throw new Error('Malformed Packet: Not enough bytes for timetag');
|
|
108
|
+
}
|
|
84
109
|
const seconds = buffer.readUInt32BE(offset);
|
|
85
110
|
const fraction = buffer.readUInt32BE(offset + 4);
|
|
86
111
|
|
|
@@ -376,6 +401,9 @@ function decodeBundleFromBuffer(buffer) {
|
|
|
376
401
|
const sizeResult = readInt32(buffer, offset);
|
|
377
402
|
const size = sizeResult.value;
|
|
378
403
|
offset = sizeResult.offset;
|
|
404
|
+
if (size <= 0 || offset + size > buffer.length) {
|
|
405
|
+
throw new Error('Malformed Packet');
|
|
406
|
+
}
|
|
379
407
|
|
|
380
408
|
// Read element data
|
|
381
409
|
const elementBuffer = buffer.subarray(offset, offset + size);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-osc",
|
|
3
3
|
"description": "pyOSC inspired library for sending and receiving OSC messages",
|
|
4
|
-
"version": "11.2.
|
|
4
|
+
"version": "11.2.2",
|
|
5
5
|
"exports": {
|
|
6
6
|
"types": "./types/index.d.mts",
|
|
7
7
|
"require": "./dist/lib/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"build:types": "tsc",
|
|
29
29
|
"docs": "node scripts/generate-docs.mjs",
|
|
30
30
|
"prepublishOnly": "npm run build",
|
|
31
|
-
"lint": "eslint \"lib/**/*.mjs\" \"test/test-*.mjs\"
|
|
31
|
+
"lint": "eslint \"lib/**/*.mjs\" \"test/test-*.mjs\" \"examples/*.js\" \"examples/*.mjs\" \"scripts/*.mjs\" rollup.config.mjs",
|
|
32
32
|
"test": "npm run lint && npm run build && npm run test:esm && npm run test:cjs",
|
|
33
33
|
"test:esm": "tap test/test-*.mjs",
|
|
34
34
|
"test:cjs": "tap dist/test/test-*.js"
|
package/test/test-bundle.mjs
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { once } from 'node:events';
|
|
2
|
+
import { test } from 'tap';
|
|
2
3
|
|
|
3
4
|
import { Client, Server, Bundle } from 'node-osc';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const server = new Server(t.context.port, '127.0.0.1');
|
|
10
|
-
const client = new Client('127.0.0.1', t.context.port);
|
|
6
|
+
test('bundle: verbose bundle', async (t) => {
|
|
7
|
+
const server = new Server(0, '127.0.0.1');
|
|
8
|
+
await once(server, 'listening');
|
|
9
|
+
const client = new Client('127.0.0.1', server.port);
|
|
11
10
|
|
|
12
11
|
t.plan(2);
|
|
13
12
|
|
|
@@ -34,9 +33,10 @@ test('bundle: verbose bundle', (t) => {
|
|
|
34
33
|
}));
|
|
35
34
|
});
|
|
36
35
|
|
|
37
|
-
test('bundle: array syntax', (t) => {
|
|
38
|
-
const server = new Server(
|
|
39
|
-
|
|
36
|
+
test('bundle: array syntax', async (t) => {
|
|
37
|
+
const server = new Server(0, '127.0.0.1');
|
|
38
|
+
await once(server, 'listening');
|
|
39
|
+
const client = new Client('127.0.0.1', server.port);
|
|
40
40
|
|
|
41
41
|
t.plan(2);
|
|
42
42
|
|
|
@@ -56,9 +56,10 @@ test('bundle: array syntax', (t) => {
|
|
|
56
56
|
));
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
test('bundle: nested bundle', (t) => {
|
|
60
|
-
const server = new Server(
|
|
61
|
-
|
|
59
|
+
test('bundle: nested bundle', async (t) => {
|
|
60
|
+
const server = new Server(0, '127.0.0.1');
|
|
61
|
+
await once(server, 'listening');
|
|
62
|
+
const client = new Client('127.0.0.1', server.port);
|
|
62
63
|
|
|
63
64
|
t.plan(4);
|
|
64
65
|
|