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
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_events = require('node:events');
|
|
4
|
+
var tap = require('tap');
|
|
5
|
+
var util = require('./util.js');
|
|
6
|
+
var nodeOsc = require('node-osc');
|
|
7
|
+
|
|
8
|
+
tap.beforeEach(util.bootstrap);
|
|
9
|
+
|
|
10
|
+
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);
|
|
13
|
+
|
|
14
|
+
t.plan(1);
|
|
15
|
+
|
|
16
|
+
oscServer.on('message', (msg) => {
|
|
17
|
+
oscServer.close();
|
|
18
|
+
t.same(msg, ['/test', 0, 1, 'testing', true], 'We should receive expected payload');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
await client.send(['/test', 0, 1, 'testing', true]);
|
|
22
|
+
await client.close();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
tap.test('client: send with promise - string', 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);
|
|
28
|
+
|
|
29
|
+
t.plan(1);
|
|
30
|
+
|
|
31
|
+
oscServer.on('message', (msg) => {
|
|
32
|
+
oscServer.close();
|
|
33
|
+
t.same(msg, ['/test'], 'We should receive expected payload');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
await client.send('/test');
|
|
37
|
+
await client.close();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
tap.test('client: send with promise - message object', async (t) => {
|
|
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);
|
|
43
|
+
|
|
44
|
+
t.plan(1);
|
|
45
|
+
|
|
46
|
+
oscServer.on('message', (msg) => {
|
|
47
|
+
oscServer.close();
|
|
48
|
+
t.same(msg, ['/test', 1, 2, 3, 'lol', false], 'we received the payload');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await client.send({
|
|
52
|
+
address: '/test',
|
|
53
|
+
args: [1, 2, 3, 'lol', false]
|
|
54
|
+
});
|
|
55
|
+
await client.close();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
tap.test('client: send with promise - multiple args', async (t) => {
|
|
59
|
+
const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
|
|
60
|
+
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
|
61
|
+
|
|
62
|
+
t.plan(1);
|
|
63
|
+
|
|
64
|
+
oscServer.on('message', (msg) => {
|
|
65
|
+
oscServer.close();
|
|
66
|
+
t.same(msg, ['/test', 1, 2, 'testing'], 'We should receive expected payload');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
await client.send('/test', 1, 2, 'testing');
|
|
70
|
+
await client.close();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
tap.test('client: send promise rejection on closed socket', async (t) => {
|
|
74
|
+
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
|
75
|
+
|
|
76
|
+
t.plan(1);
|
|
77
|
+
|
|
78
|
+
await client.close();
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await client.send('/boom');
|
|
82
|
+
t.fail('Should have thrown an error');
|
|
83
|
+
} catch (err) {
|
|
84
|
+
t.equal(err.code, 'ERR_SOCKET_DGRAM_NOT_RUNNING', 'Should reject with correct error code');
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
tap.test('client: async/await usage', async (t) => {
|
|
89
|
+
const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
|
|
90
|
+
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
|
91
|
+
|
|
92
|
+
t.plan(1);
|
|
93
|
+
|
|
94
|
+
const messagePromise = node_events.once(oscServer, 'message');
|
|
95
|
+
|
|
96
|
+
await client.send('/async-test', 42, 'hello');
|
|
97
|
+
const [receivedMessage] = await messagePromise;
|
|
98
|
+
|
|
99
|
+
t.same(receivedMessage, ['/async-test', 42, 'hello'], 'Message received via async/await');
|
|
100
|
+
|
|
101
|
+
await client.close();
|
|
102
|
+
await oscServer.close();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
tap.test('server: close with promise', async (t) => {
|
|
106
|
+
const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
|
|
107
|
+
|
|
108
|
+
t.plan(1);
|
|
109
|
+
|
|
110
|
+
await node_events.once(oscServer, 'listening');
|
|
111
|
+
|
|
112
|
+
await oscServer.close();
|
|
113
|
+
t.pass('Server closed successfully with promise');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
tap.test('server: no callback still emits listening event', async (t) => {
|
|
117
|
+
const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
|
|
118
|
+
|
|
119
|
+
t.plan(1);
|
|
120
|
+
|
|
121
|
+
await node_events.once(oscServer, 'listening');
|
|
122
|
+
t.pass('listening event emitted');
|
|
123
|
+
|
|
124
|
+
await oscServer.close();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
tap.test('client and server: full async/await workflow', async (t) => {
|
|
128
|
+
const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
|
|
129
|
+
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
|
130
|
+
|
|
131
|
+
t.plan(2);
|
|
132
|
+
|
|
133
|
+
// Wait for server to be ready
|
|
134
|
+
await node_events.once(oscServer, 'listening');
|
|
135
|
+
t.pass('Server started');
|
|
136
|
+
|
|
137
|
+
// Set up message handler
|
|
138
|
+
const messageReceived = node_events.once(oscServer, 'message');
|
|
139
|
+
|
|
140
|
+
// Send message and wait for it to be received
|
|
141
|
+
await client.send('/workflow', 'test', 123);
|
|
142
|
+
const [msg] = await messageReceived;
|
|
143
|
+
t.same(msg, ['/workflow', 'test', 123], 'Message received correctly');
|
|
144
|
+
|
|
145
|
+
// Clean up
|
|
146
|
+
await client.close();
|
|
147
|
+
await oscServer.close();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
tap.test('client: multiple sends with promises', async (t) => {
|
|
151
|
+
const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
|
|
152
|
+
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
|
153
|
+
|
|
154
|
+
t.plan(3);
|
|
155
|
+
|
|
156
|
+
const messages = [];
|
|
157
|
+
oscServer.on('message', (msg) => {
|
|
158
|
+
messages.push(msg);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await client.send('/msg1', 1);
|
|
162
|
+
await client.send('/msg2', 2);
|
|
163
|
+
await client.send('/msg3', 3);
|
|
164
|
+
|
|
165
|
+
// Give a little time for all messages to be received
|
|
166
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
167
|
+
|
|
168
|
+
t.equal(messages.length, 3, 'Received all three messages');
|
|
169
|
+
t.same(messages[0], ['/msg1', 1], 'First message correct');
|
|
170
|
+
t.same(messages[2], ['/msg3', 3], 'Last message correct');
|
|
171
|
+
|
|
172
|
+
await client.close();
|
|
173
|
+
await oscServer.close();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
tap.test('client: close promise rejection on error', async (t) => {
|
|
177
|
+
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
|
178
|
+
|
|
179
|
+
t.plan(1);
|
|
180
|
+
|
|
181
|
+
// Mock the socket's close method to simulate an error
|
|
182
|
+
const originalClose = client._sock.close.bind(client._sock);
|
|
183
|
+
|
|
184
|
+
// Set up teardown to ensure socket is properly closed
|
|
185
|
+
t.teardown(() => {
|
|
186
|
+
// Restore original close method first
|
|
187
|
+
client._sock.close = originalClose;
|
|
188
|
+
// Then close the socket
|
|
189
|
+
try {
|
|
190
|
+
client._sock.close(() => {});
|
|
191
|
+
} catch {
|
|
192
|
+
// Socket might already be closed, that's ok
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
client._sock.close = function(cb) {
|
|
197
|
+
// Simulate an error being passed to callback
|
|
198
|
+
if (cb) {
|
|
199
|
+
const err = new Error('Mock close error');
|
|
200
|
+
err.code = 'MOCK_ERROR';
|
|
201
|
+
setImmediate(() => cb(err));
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
await client.close();
|
|
207
|
+
t.fail('Should have thrown an error');
|
|
208
|
+
} catch (err) {
|
|
209
|
+
t.equal(err.code, 'MOCK_ERROR', 'Should reject with mock error');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
tap.test('server: close promise rejection on error', async (t) => {
|
|
214
|
+
const oscServer = new nodeOsc.Server(t.context.port, '127.0.0.1');
|
|
215
|
+
|
|
216
|
+
t.plan(1);
|
|
217
|
+
|
|
218
|
+
await node_events.once(oscServer, 'listening');
|
|
219
|
+
|
|
220
|
+
// Mock the socket's close method to simulate an error
|
|
221
|
+
const originalClose = oscServer._sock.close.bind(oscServer._sock);
|
|
222
|
+
|
|
223
|
+
// Set up teardown to ensure socket is properly closed
|
|
224
|
+
t.teardown(() => {
|
|
225
|
+
// Restore original close method first
|
|
226
|
+
oscServer._sock.close = originalClose;
|
|
227
|
+
// Then close the socket
|
|
228
|
+
try {
|
|
229
|
+
oscServer._sock.close(() => {});
|
|
230
|
+
} catch {
|
|
231
|
+
// Socket might already be closed, that's ok
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
oscServer._sock.close = function(cb) {
|
|
236
|
+
// Simulate an error being passed to callback
|
|
237
|
+
if (cb) {
|
|
238
|
+
const err = new Error('Mock close error');
|
|
239
|
+
err.code = 'MOCK_ERROR';
|
|
240
|
+
setImmediate(() => cb(err));
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
await oscServer.close();
|
|
246
|
+
t.fail('Should have thrown an error');
|
|
247
|
+
} catch (err) {
|
|
248
|
+
t.equal(err.code, 'MOCK_ERROR', 'Should reject with mock error');
|
|
249
|
+
}
|
|
250
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tap = require('tap');
|
|
4
|
+
var node_child_process = require('node:child_process');
|
|
5
|
+
var node_path = require('node:path');
|
|
6
|
+
var node_url = require('node:url');
|
|
7
|
+
|
|
8
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
9
|
+
const __dirname$1 = node_url.fileURLToPath(new URL('.', (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('test-types.js', document.baseURI).href))));
|
|
10
|
+
|
|
11
|
+
// Only run in ESM mode (not when transpiled to CJS in dist/)
|
|
12
|
+
// Normalize path separators for cross-platform compatibility
|
|
13
|
+
const normalizedPath = __dirname$1.replace(/\\/g, '/');
|
|
14
|
+
const isESM = !normalizedPath.includes('/dist/');
|
|
15
|
+
|
|
16
|
+
tap.test('types: TypeScript compilation', (t) => {
|
|
17
|
+
let tsconfigPath;
|
|
18
|
+
const testRoot = node_path.resolve(__dirname$1, isESM ? '.': '../../test');
|
|
19
|
+
if (isESM) {
|
|
20
|
+
tsconfigPath = node_path.join(testRoot, 'fixtures', 'types', 'tsconfig-esm.test.json');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
tsconfigPath = node_path.join(testRoot, 'fixtures', 'types', 'tsconfig-cjs.test.json');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Run TypeScript compiler
|
|
28
|
+
const cmd = 'npx tsc --project "' + tsconfigPath + '"';
|
|
29
|
+
node_child_process.execSync(cmd, {
|
|
30
|
+
encoding: 'utf-8',
|
|
31
|
+
stdio: 'pipe',
|
|
32
|
+
cwd: node_path.join(testRoot, 'fixtures', 'types')
|
|
33
|
+
});
|
|
34
|
+
t.pass('TypeScript types compile successfully');
|
|
35
|
+
} catch (error) {
|
|
36
|
+
t.fail('TypeScript compilation failed: ' + error.message);
|
|
37
|
+
if (error.stdout) console.log('STDOUT:', error.stdout);
|
|
38
|
+
if (error.stderr) console.log('STDERR:', error.stderr);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
t.end();
|
|
42
|
+
});
|
package/dist/test/util.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var node_net = require('node:net');
|
|
4
|
+
var promises = require('node:timers/promises');
|
|
4
5
|
|
|
5
6
|
async function bootstrap(t) {
|
|
6
7
|
const port = await getPort();
|
|
@@ -9,18 +10,24 @@ async function bootstrap(t) {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
function getPort() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
async function getPort() {
|
|
14
|
+
const server = node_net.createServer();
|
|
15
|
+
server.unref();
|
|
16
|
+
|
|
17
|
+
const port = await new Promise((resolve, reject) => {
|
|
16
18
|
server.on('error', reject);
|
|
17
19
|
server.listen(() => {
|
|
18
|
-
|
|
19
|
-
server.close(() => {
|
|
20
|
-
resolve(port);
|
|
21
|
-
});
|
|
20
|
+
resolve(server.address().port);
|
|
22
21
|
});
|
|
23
22
|
});
|
|
23
|
+
|
|
24
|
+
await server.close();
|
|
25
|
+
|
|
26
|
+
// Allow the event loop to process and ensure port is fully released
|
|
27
|
+
// This prevents EACCES errors when immediately rebinding to the same port
|
|
28
|
+
await promises.setImmediate();
|
|
29
|
+
|
|
30
|
+
return port;
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
exports.bootstrap = bootstrap;
|