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.
Files changed (40) hide show
  1. package/.github/workflows/nodejs.yml +1 -1
  2. package/README.md +3 -2
  3. package/agent.md +330 -0
  4. package/dist/lib/Server.js +7 -12
  5. package/dist/lib/internal/decode.js +3 -1
  6. package/dist/lib/osc.js +29 -1
  7. package/dist/test/lib/osc.js +29 -1
  8. package/dist/test/test-bundle.js +13 -12
  9. package/dist/test/test-client.js +49 -40
  10. package/dist/test/test-decode.js +35 -0
  11. package/dist/test/test-e2e.js +9 -9
  12. package/dist/test/test-encode-decode.js +96 -0
  13. package/dist/test/test-error-handling.js +14 -13
  14. package/dist/test/test-message.js +169 -119
  15. package/dist/test/test-osc-internal.js +151 -0
  16. package/dist/test/test-promises.js +71 -29
  17. package/dist/test/test-server.js +19 -16
  18. package/docs/README.md +81 -0
  19. package/examples/README.md +3 -1
  20. package/lib/Server.mjs +7 -12
  21. package/lib/internal/decode.mjs +3 -1
  22. package/lib/osc.mjs +29 -1
  23. package/package.json +2 -2
  24. package/test/test-bundle.mjs +14 -13
  25. package/test/test-client.mjs +50 -41
  26. package/test/test-decode.mjs +35 -0
  27. package/test/test-e2e.mjs +10 -10
  28. package/test/test-encode-decode.mjs +96 -0
  29. package/test/test-error-handling.mjs +15 -14
  30. package/test/test-message.mjs +171 -122
  31. package/test/test-osc-internal.mjs +151 -0
  32. package/test/test-promises.mjs +72 -30
  33. package/test/test-server.mjs +20 -17
  34. package/types/Server.d.mts.map +1 -1
  35. package/types/internal/decode.d.mts.map +1 -1
  36. package/types/osc.d.mts.map +1 -1
  37. package/dist/test/test-getPort.js +0 -20
  38. package/dist/test/util.js +0 -34
  39. package/test/test-getPort.mjs +0 -18
  40. 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 oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
12
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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
- oscServer.on('message', (msg) => {
17
- oscServer.close();
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(t.context.port, '127.0.0.1');
27
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
49
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
64
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
82
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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 client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
112
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
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(t.context.port, '127.0.0.1');
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
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
151
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
174
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
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
+ });
@@ -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.beforeEach(util.bootstrap);
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(t.context.port, '127.0.0.1');
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(t.context.port);
19
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port);
43
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, () => {
68
+ const oscServer = new nodeOsc.Server(0, () => {
68
69
  t.ok('callback called');
69
70
  });
70
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
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.
@@ -115,5 +115,7 @@ Demonstrates:
115
115
  ## Further Reading
116
116
 
117
117
  - [Main README](../README.md) - Quick start guide
118
- - [API Documentation](../docs/API.md) - Complete API reference
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
- // Support both callback and promise-based listening
94
- if (cb) {
95
- this._sock.on('listening', () => {
96
- this.emit('listening');
97
- cb();
98
- });
99
- } else {
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 {
@@ -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.forEach(arg => {
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 (typeof value === 'number') {
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.1",
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\" test/util.mjs examples/*.js examples/*.mjs rollup.config.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"
@@ -1,13 +1,12 @@
1
- import { beforeEach, test } from 'tap';
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
- import { bootstrap } from './util.mjs';
6
- beforeEach(bootstrap);
7
-
8
- test('bundle: verbose bundle', (t) => {
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(t.context.port, '127.0.0.1');
39
- const client = new Client('127.0.0.1', t.context.port);
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(t.context.port, '127.0.0.1');
61
- const client = new Client('127.0.0.1', t.context.port);
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