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
@@ -1,14 +1,13 @@
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('client: with array', (t) => {
10
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
11
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
7
+ tap.test('client: with array', async (t) => {
8
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
9
+ await node_events.once(oscServer, 'listening');
10
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
12
11
 
13
12
  t.plan(2);
14
13
 
@@ -23,9 +22,10 @@ tap.test('client: with array', (t) => {
23
22
  });
24
23
  });
25
24
 
26
- tap.test('client: array is not mutated when sent', (t) => {
27
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
28
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
25
+ tap.test('client: array is not mutated when sent', async (t) => {
26
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
27
+ await node_events.once(oscServer, 'listening');
28
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
29
29
 
30
30
  t.plan(3);
31
31
 
@@ -45,9 +45,10 @@ tap.test('client: array is not mutated when sent', (t) => {
45
45
  });
46
46
  });
47
47
 
48
- tap.test('client: with string', (t) => {
49
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
50
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
48
+ tap.test('client: with string', async (t) => {
49
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
50
+ await node_events.once(oscServer, 'listening');
51
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
51
52
 
52
53
  t.plan(2);
53
54
 
@@ -62,9 +63,10 @@ tap.test('client: with string', (t) => {
62
63
  });
63
64
  });
64
65
 
65
- tap.test('client: with Message object', (t) => {
66
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
67
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
66
+ tap.test('client: with Message object', async (t) => {
67
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
68
+ await node_events.once(oscServer, 'listening');
69
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
68
70
 
69
71
  t.plan(2);
70
72
 
@@ -88,9 +90,10 @@ tap.test('client: with Message object', (t) => {
88
90
  });
89
91
  });
90
92
 
91
- tap.test('client: with Bundle object', (t) => {
92
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
93
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
93
+ tap.test('client: with Bundle object', async (t) => {
94
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
95
+ await node_events.once(oscServer, 'listening');
96
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
94
97
 
95
98
  t.plan(2);
96
99
 
@@ -114,8 +117,8 @@ tap.test('client: with Bundle object', (t) => {
114
117
  });
115
118
  });
116
119
 
117
- tap.test('client: failure', (t) => {
118
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
120
+ tap.test('client: failure', async (t) => {
121
+ const client = new nodeOsc.Client('127.0.0.1', 9999);
119
122
 
120
123
  t.plan(2);
121
124
 
@@ -130,8 +133,8 @@ tap.test('client: failure', (t) => {
130
133
  });
131
134
  });
132
135
 
133
- tap.test('client: close with callback', (t) => {
134
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
136
+ tap.test('client: close with callback', async (t) => {
137
+ const client = new nodeOsc.Client('127.0.0.1', 9999);
135
138
 
136
139
  t.plan(1);
137
140
 
@@ -140,9 +143,10 @@ tap.test('client: close with callback', (t) => {
140
143
  });
141
144
  });
142
145
 
143
- tap.test('client: send bundle with non-numeric timetag', (t) => {
144
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
145
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
146
+ tap.test('client: send bundle with non-numeric timetag', async (t) => {
147
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
148
+ await node_events.once(oscServer, 'listening');
149
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
146
150
 
147
151
  t.plan(2);
148
152
 
@@ -169,9 +173,10 @@ tap.test('client: send bundle with non-numeric timetag', (t) => {
169
173
  client.send(bundle);
170
174
  });
171
175
 
172
- tap.test('client: send bundle with null timetag', (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);
176
+ tap.test('client: send bundle with null timetag', async (t) => {
177
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
178
+ await node_events.once(oscServer, 'listening');
179
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
175
180
 
176
181
  t.plan(2);
177
182
 
@@ -198,9 +203,10 @@ tap.test('client: send bundle with null timetag', (t) => {
198
203
  client.send(bundle);
199
204
  });
200
205
 
201
- tap.test('client: send message with float type arg', (t) => {
202
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
203
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
206
+ tap.test('client: send message with float type arg', async (t) => {
207
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
208
+ await node_events.once(oscServer, 'listening');
209
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
204
210
 
205
211
  t.plan(2);
206
212
 
@@ -219,9 +225,10 @@ tap.test('client: send message with float type arg', (t) => {
219
225
  });
220
226
  });
221
227
 
222
- tap.test('client: send message with blob type arg', (t) => {
223
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
224
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
228
+ tap.test('client: send message with blob type arg', async (t) => {
229
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
230
+ await node_events.once(oscServer, 'listening');
231
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
225
232
 
226
233
  t.plan(2);
227
234
 
@@ -240,9 +247,10 @@ tap.test('client: send message with blob type arg', (t) => {
240
247
  });
241
248
  });
242
249
 
243
- tap.test('client: send message with double type arg', (t) => {
244
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
245
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
250
+ tap.test('client: send message with double type arg', async (t) => {
251
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
252
+ await node_events.once(oscServer, 'listening');
253
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
246
254
 
247
255
  t.plan(2);
248
256
 
@@ -261,9 +269,10 @@ tap.test('client: send message with double type arg', (t) => {
261
269
  });
262
270
  });
263
271
 
264
- tap.test('client: send message with midi type arg', (t) => {
265
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
266
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
272
+ tap.test('client: send message with midi type arg', async (t) => {
273
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
274
+ await node_events.once(oscServer, 'listening');
275
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
267
276
 
268
277
  t.plan(2);
269
278
 
@@ -107,3 +107,38 @@ tap.test('decode: malformed structure with unexpected oscType', async (t) => {
107
107
 
108
108
  t.end();
109
109
  });
110
+
111
+ tap.test('decode: message without args defaults to empty array', (t) => {
112
+ const mockFromBuffer = () => ({
113
+ oscType: 'message',
114
+ address: '/test'
115
+ });
116
+
117
+ t.same(
118
+ decode(Buffer.from('test'), mockFromBuffer),
119
+ ['/test'],
120
+ 'should default args to empty array'
121
+ );
122
+ t.end();
123
+ });
124
+
125
+ tap.test('decode: bundle element must be message or bundle', (t) => {
126
+ const mockFromBuffer = () => ({
127
+ oscType: 'bundle',
128
+ elements: [
129
+ {
130
+ oscType: 'message',
131
+ address: '/ok',
132
+ args: []
133
+ },
134
+ {
135
+ oscType: 'nope'
136
+ }
137
+ ]
138
+ });
139
+
140
+ t.throws(() => {
141
+ decode(Buffer.from('test'), mockFromBuffer);
142
+ }, /Malformed Packet/, 'should throw for invalid bundle element');
143
+ t.end();
144
+ });
@@ -1,11 +1,9 @@
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
7
  function flaky() {
10
8
  return process.release.lts === 'Dubnium' && process.platform === 'win32';
11
9
  }
@@ -15,11 +13,12 @@ function skip(t) {
15
13
  t.end();
16
14
  }
17
15
 
18
- tap.test('osc: argument message no callback', (t) => {
16
+ tap.test('osc: argument message no callback', async (t) => {
19
17
  if (flaky()) return skip(t);
20
18
 
21
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
22
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
19
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
20
+ await node_events.once(oscServer, 'listening');
21
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
23
22
 
24
23
  t.plan(1);
25
24
 
@@ -35,11 +34,12 @@ tap.test('osc: argument message no callback', (t) => {
35
34
  client.send('/test', 1, 2, 'testing');
36
35
  });
37
36
 
38
- tap.test('osc: client with callback and message as arguments', (t) => {
37
+ tap.test('osc: client with callback and message as arguments', async (t) => {
39
38
  if (flaky()) return skip(t);
40
39
 
41
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
42
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
40
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
41
+ await node_events.once(oscServer, 'listening');
42
+ const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
43
43
 
44
44
  t.plan(2);
45
45
 
@@ -295,6 +295,102 @@ tap.test('decode: error on malformed type tags (no leading comma)', (t) => {
295
295
  t.end();
296
296
  });
297
297
 
298
+ tap.test('decode: error on truncated blob data', (t) => {
299
+ const addressBuf = Buffer.from('/b\0\0', 'ascii');
300
+ const typeTagsBuf = Buffer.from(',b\0\0', 'ascii');
301
+ const lengthBuf = Buffer.alloc(4);
302
+ lengthBuf.writeInt32BE(4, 0);
303
+ const dataBuf = Buffer.from([0x01, 0x02]);
304
+ const buffer = Buffer.concat([addressBuf, typeTagsBuf, lengthBuf, dataBuf]);
305
+
306
+ t.throws(() => {
307
+ nodeOsc.decode(buffer);
308
+ }, /Malformed Packet: Not enough bytes for blob/, 'should throw when blob data is truncated');
309
+
310
+ t.end();
311
+ });
312
+
313
+ tap.test('decode: error on missing blob padding', (t) => {
314
+ const addressBuf = Buffer.from('/b\0\0', 'ascii');
315
+ const typeTagsBuf = Buffer.from(',b\0\0', 'ascii');
316
+ const lengthBuf = Buffer.alloc(4);
317
+ lengthBuf.writeInt32BE(3, 0);
318
+ const dataBuf = Buffer.from([0x01, 0x02, 0x03]);
319
+ const buffer = Buffer.concat([addressBuf, typeTagsBuf, lengthBuf, dataBuf]);
320
+
321
+ t.throws(() => {
322
+ nodeOsc.decode(buffer);
323
+ }, /Malformed Packet: Not enough bytes for blob padding/, 'should throw when blob padding is missing');
324
+
325
+ t.end();
326
+ });
327
+
328
+ tap.test('decode: error on truncated float32', (t) => {
329
+ const addressBuf = Buffer.from('/f\0\0', 'ascii');
330
+ const typeTagsBuf = Buffer.from(',f\0\0', 'ascii');
331
+ const dataBuf = Buffer.from([0x3f, 0x80, 0x00]);
332
+ const buffer = Buffer.concat([addressBuf, typeTagsBuf, dataBuf]);
333
+
334
+ t.throws(() => {
335
+ nodeOsc.decode(buffer);
336
+ }, /Malformed Packet: Not enough bytes for float32/, 'should throw when float32 data is truncated');
337
+
338
+ t.end();
339
+ });
340
+
341
+ tap.test('decode: error on truncated int32', (t) => {
342
+ const addressBuf = Buffer.from('/i\0\0', 'ascii');
343
+ const typeTagsBuf = Buffer.from(',i\0\0', 'ascii');
344
+ const dataBuf = Buffer.from([0x00, 0x01]);
345
+ const buffer = Buffer.concat([addressBuf, typeTagsBuf, dataBuf]);
346
+
347
+ t.throws(() => {
348
+ nodeOsc.decode(buffer);
349
+ }, /Malformed Packet: Not enough bytes for int32/, 'should throw when int32 data is truncated');
350
+
351
+ t.end();
352
+ });
353
+
354
+ tap.test('decode: error on negative blob length', (t) => {
355
+ const addressBuf = Buffer.from('/b\0\0', 'ascii');
356
+ const typeTagsBuf = Buffer.from(',b\0\0', 'ascii');
357
+ const lengthBuf = Buffer.alloc(4);
358
+ lengthBuf.writeInt32BE(-1, 0);
359
+ const buffer = Buffer.concat([addressBuf, typeTagsBuf, lengthBuf]);
360
+
361
+ t.throws(() => {
362
+ nodeOsc.decode(buffer);
363
+ }, /Malformed Packet: Invalid blob length/, 'should throw when blob length is negative');
364
+
365
+ t.end();
366
+ });
367
+
368
+ tap.test('decode: error on bundle element size overflow', (t) => {
369
+ const bundleHeader = Buffer.from('#bundle\0', 'ascii');
370
+ const timetag = Buffer.alloc(8);
371
+ const sizeBuf = Buffer.alloc(4);
372
+ sizeBuf.writeInt32BE(0, 0);
373
+ const buffer = Buffer.concat([bundleHeader, timetag, sizeBuf]);
374
+
375
+ t.throws(() => {
376
+ nodeOsc.decode(buffer);
377
+ }, /Malformed Packet/, 'should throw when bundle element size is invalid');
378
+
379
+ t.end();
380
+ });
381
+
382
+ tap.test('decode: error on truncated bundle timetag', (t) => {
383
+ const bundleHeader = Buffer.from('#bundle\0', 'ascii');
384
+ const timetag = Buffer.alloc(4);
385
+ const buffer = Buffer.concat([bundleHeader, timetag]);
386
+
387
+ t.throws(() => {
388
+ nodeOsc.decode(buffer);
389
+ }, /Malformed Packet: Not enough bytes for timetag/, 'should throw when timetag is truncated');
390
+
391
+ t.end();
392
+ });
393
+
298
394
  tap.test('encode and decode: nested bundle with message and bundle elements', (t) => {
299
395
  // Test the else branch in encodeBundleToBuffer for message elements
300
396
  const innerBundle = new nodeOsc.Bundle(['/inner/message', 123]);
@@ -1,14 +1,13 @@
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: socket error event is emitted', (t) => {
7
+ tap.test('server: socket error event is emitted', 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
 
13
12
  oscServer.on('error', (err) => {
14
13
  t.ok(err, 'error event should be emitted');
@@ -19,9 +18,10 @@ tap.test('server: socket error event is emitted', (t) => {
19
18
  oscServer._sock.emit('error', new Error('test socket error'));
20
19
  });
21
20
 
22
- tap.test('server: error listener can be added before listening', (t) => {
21
+ tap.test('server: error listener can be added before listening', async (t) => {
23
22
  t.plan(2);
24
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
23
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
24
+ await node_events.once(oscServer, 'listening');
25
25
 
26
26
  oscServer.on('error', (err) => {
27
27
  t.ok(err, 'error event should be emitted');
@@ -38,7 +38,7 @@ tap.test('server: error listener can be added before listening', (t) => {
38
38
 
39
39
  tap.test('client: socket error event is emitted', (t) => {
40
40
  t.plan(1);
41
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
41
+ const client = new nodeOsc.Client('127.0.0.1', 9999);
42
42
 
43
43
  client.on('error', (err) => {
44
44
  t.ok(err, 'error event should be emitted');
@@ -51,7 +51,7 @@ tap.test('client: socket error event is emitted', (t) => {
51
51
 
52
52
  tap.test('client: error listener can be added at construction', (t) => {
53
53
  t.plan(2);
54
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
54
+ const client = new nodeOsc.Client('127.0.0.1', 9999);
55
55
 
56
56
  client.on('error', (err) => {
57
57
  t.ok(err, 'error event should be emitted');
@@ -68,16 +68,17 @@ tap.test('client: error listener can be added at construction', (t) => {
68
68
 
69
69
  tap.test('client: is an EventEmitter instance', (t) => {
70
70
  t.plan(1);
71
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
71
+ const client = new nodeOsc.Client('127.0.0.1', 9999);
72
72
 
73
73
  t.ok(typeof client.on === 'function', 'client should have EventEmitter methods');
74
74
 
75
75
  client.close();
76
76
  });
77
77
 
78
- tap.test('server: multiple error listeners can be attached', (t) => {
78
+ tap.test('server: multiple error listeners can be attached', async (t) => {
79
79
  t.plan(2);
80
- const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
80
+ const oscServer = new nodeOsc.Server(0, '127.0.0.1');
81
+ await node_events.once(oscServer, 'listening');
81
82
 
82
83
  oscServer.on('error', (err) => {
83
84
  t.ok(err, 'first listener should receive error');
@@ -97,7 +98,7 @@ tap.test('server: multiple error listeners can be attached', (t) => {
97
98
 
98
99
  tap.test('client: multiple error listeners can be attached', (t) => {
99
100
  t.plan(2);
100
- const client = new nodeOsc.Client('127.0.0.1', t.context.port);
101
+ const client = new nodeOsc.Client('127.0.0.1', 9999);
101
102
 
102
103
  client.on('error', (err) => {
103
104
  t.ok(err, 'first listener should receive error');