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