node-osc 11.1.1 → 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/dist/lib/{internal/osc.js → osc.js} +70 -5
- 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/lib/{internal/osc.mjs → osc.mjs} +71 -4
- package/package.json +12 -10
- package/rollup.config.mjs +48 -41
- 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
package/rollup.config.mjs
CHANGED
|
@@ -20,52 +20,59 @@ function walk(root, result=[]) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function walkLib(config) {
|
|
23
|
+
// Build all lib files in a single pass
|
|
23
24
|
const files = walk('./lib/');
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
]
|
|
42
|
-
});
|
|
25
|
+
config.push({
|
|
26
|
+
input: files.map(f => f.input),
|
|
27
|
+
output: {
|
|
28
|
+
entryFileNames: '[name].js',
|
|
29
|
+
dir: 'dist/lib',
|
|
30
|
+
format: 'cjs',
|
|
31
|
+
preserveModules: true,
|
|
32
|
+
preserveModulesRoot: 'lib',
|
|
33
|
+
exports: 'auto'
|
|
34
|
+
},
|
|
35
|
+
external: [
|
|
36
|
+
'node:dgram',
|
|
37
|
+
'node:events',
|
|
38
|
+
'node:buffer',
|
|
39
|
+
'jspack',
|
|
40
|
+
'#decode'
|
|
41
|
+
]
|
|
43
42
|
});
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
function walkTest(config) {
|
|
47
|
-
|
|
48
|
-
tests.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
46
|
+
// Build all test files in a single pass, excluding fixtures
|
|
47
|
+
const tests = walk('./test/').filter(t => {
|
|
48
|
+
// Normalize path separators to work on both Unix and Windows
|
|
49
|
+
const normalizedPath = t.input.replace(/\\/g, '/');
|
|
50
|
+
return !normalizedPath.includes('/fixtures/');
|
|
51
|
+
});
|
|
52
|
+
config.push({
|
|
53
|
+
input: tests.map(t => t.input),
|
|
54
|
+
plugins: [],
|
|
55
|
+
output: {
|
|
56
|
+
entryFileNames: '[name].js',
|
|
57
|
+
dir: 'dist/test',
|
|
58
|
+
format: 'cjs',
|
|
59
|
+
exports: 'auto',
|
|
60
|
+
preserveModules: true,
|
|
61
|
+
preserveModulesRoot: 'test'
|
|
62
|
+
},
|
|
63
|
+
external: [
|
|
64
|
+
'node:dgram',
|
|
65
|
+
'node:net',
|
|
66
|
+
'node:buffer',
|
|
67
|
+
'node:events',
|
|
68
|
+
'node:child_process',
|
|
69
|
+
'node:fs',
|
|
70
|
+
'node:path',
|
|
71
|
+
'node:url',
|
|
72
|
+
'node-osc',
|
|
73
|
+
'tap',
|
|
74
|
+
'#decode'
|
|
75
|
+
]
|
|
69
76
|
});
|
|
70
77
|
}
|
|
71
78
|
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts JSDoc JSON output to Markdown documentation.
|
|
5
|
+
* This script reads JSDoc JSON data and generates a formatted Markdown file.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { writeFileSync } from 'node:fs';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
|
|
11
|
+
// Generate JSDoc JSON
|
|
12
|
+
let jsdocJson;
|
|
13
|
+
try {
|
|
14
|
+
jsdocJson = execSync('npx jsdoc -X -c jsdoc.json', {
|
|
15
|
+
encoding: 'utf8',
|
|
16
|
+
maxBuffer: 10 * 1024 * 1024
|
|
17
|
+
});
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error('❌ Failed to run JSDoc:');
|
|
20
|
+
console.error(error.message);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let docs;
|
|
25
|
+
try {
|
|
26
|
+
docs = JSON.parse(jsdocJson);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error('❌ Failed to parse JSDoc JSON output:');
|
|
29
|
+
console.error(error.message);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Filter and organize documentation
|
|
34
|
+
const classes = {};
|
|
35
|
+
const functions = {};
|
|
36
|
+
|
|
37
|
+
docs.forEach(item => {
|
|
38
|
+
if (item.undocumented || item.ignore) return;
|
|
39
|
+
|
|
40
|
+
if (item.kind === 'class' && item.classdesc) {
|
|
41
|
+
if (!classes[item.name]) {
|
|
42
|
+
classes[item.name] = {
|
|
43
|
+
desc: item.classdesc,
|
|
44
|
+
constructor: null,
|
|
45
|
+
methods: [],
|
|
46
|
+
examples: item.examples || [],
|
|
47
|
+
augments: item.augments || []
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// Look for constructor params
|
|
51
|
+
if (item.params) {
|
|
52
|
+
classes[item.name].constructor = {
|
|
53
|
+
params: item.params,
|
|
54
|
+
examples: item.examples || []
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
} else if (item.kind === 'function' && item.memberof) {
|
|
58
|
+
// Method of a class
|
|
59
|
+
const className = item.memberof;
|
|
60
|
+
if (!classes[className]) {
|
|
61
|
+
classes[className] = {
|
|
62
|
+
desc: '',
|
|
63
|
+
constructor: null,
|
|
64
|
+
methods: [],
|
|
65
|
+
examples: []
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
classes[className].methods.push(item);
|
|
69
|
+
} else if (item.kind === 'function' && !item.memberof && item.scope === 'global') {
|
|
70
|
+
// Top-level function
|
|
71
|
+
functions[item.name] = item;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Generate Markdown
|
|
76
|
+
let markdown = `<!-- Generated by JSDoc. Update this documentation by updating the source code. -->
|
|
77
|
+
|
|
78
|
+
# API Reference
|
|
79
|
+
|
|
80
|
+
> **⚠️ This file is auto-generated from JSDoc comments in the source code.**
|
|
81
|
+
> To update this documentation, edit the JSDoc comments in the source files and run \`npm run docs\`.
|
|
82
|
+
|
|
83
|
+
This document provides detailed API reference for all classes, methods, and functions in node-osc.
|
|
84
|
+
|
|
85
|
+
For usage guides, best practices, and troubleshooting, see the **[Guide](./GUIDE.md)**.
|
|
86
|
+
|
|
87
|
+
## Table of Contents
|
|
88
|
+
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
// Define order: Server → Client → Message → Bundle → Low Level
|
|
92
|
+
const classOrder = ['Server', 'Client', 'Message', 'Bundle'];
|
|
93
|
+
const functionOrder = ['encode', 'decode'];
|
|
94
|
+
|
|
95
|
+
// Add classes to TOC
|
|
96
|
+
classOrder.forEach(name => {
|
|
97
|
+
if (classes[name]) {
|
|
98
|
+
markdown += `- [${name}](#${name.toLowerCase()})\n`;
|
|
99
|
+
if (classes[name].constructor) {
|
|
100
|
+
markdown += ` - [Constructor](#${name.toLowerCase()}-constructor)\n`;
|
|
101
|
+
}
|
|
102
|
+
classes[name].methods.forEach(method => {
|
|
103
|
+
markdown += ` - [${method.name}()](#${name.toLowerCase()}-${method.name.toLowerCase()})\n`;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Add functions to TOC
|
|
109
|
+
markdown += `- [Low Level Functions](#low-level-functions)\n`;
|
|
110
|
+
functionOrder.forEach(name => {
|
|
111
|
+
if (functions[name]) {
|
|
112
|
+
markdown += ` - [${name}()](#${name.toLowerCase()})\n`;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
markdown += `\n---\n\n`;
|
|
117
|
+
|
|
118
|
+
// Helper function to format parameters
|
|
119
|
+
function formatParams(params) {
|
|
120
|
+
if (!params || params.length === 0) return '';
|
|
121
|
+
|
|
122
|
+
let result = '\n**Parameters:**\n\n';
|
|
123
|
+
params.forEach(param => {
|
|
124
|
+
const optional = param.optional ? ' (optional)' : '';
|
|
125
|
+
const defaultVal = param.defaultvalue ? ` - Default: \`${param.defaultvalue}\`` : '';
|
|
126
|
+
const types = param.type ? param.type.names.join(' | ') : 'any';
|
|
127
|
+
result += `- \`${param.name}\` *{${types}}*${optional}${defaultVal} - ${param.description || ''}\n`;
|
|
128
|
+
});
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Helper function to format examples
|
|
133
|
+
function formatExamples(examples) {
|
|
134
|
+
if (!examples || examples.length === 0) return '';
|
|
135
|
+
|
|
136
|
+
let result = '\n**Examples:**\n\n';
|
|
137
|
+
examples.forEach(example => {
|
|
138
|
+
result += '```javascript\n' + example + '\n```\n\n';
|
|
139
|
+
});
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Helper function to format returns
|
|
144
|
+
function formatReturns(returns) {
|
|
145
|
+
if (!returns || returns.length === 0) return '';
|
|
146
|
+
|
|
147
|
+
const ret = returns[0];
|
|
148
|
+
const types = ret.type ? ret.type.names.join(' | ') : 'any';
|
|
149
|
+
return `\n**Returns:** *{${types}}* - ${ret.description || ''}\n`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Helper function to format throws
|
|
153
|
+
function formatThrows(exceptions) {
|
|
154
|
+
if (!exceptions || exceptions.length === 0) return '';
|
|
155
|
+
|
|
156
|
+
let result = '\n**Throws:**\n\n';
|
|
157
|
+
exceptions.forEach(ex => {
|
|
158
|
+
const types = ex.type ? ex.type.names.join(' | ') : 'Error';
|
|
159
|
+
result += `- *{${types}}* - ${ex.description || ''}\n`;
|
|
160
|
+
});
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Generate class documentation
|
|
165
|
+
classOrder.forEach(className => {
|
|
166
|
+
const classInfo = classes[className];
|
|
167
|
+
if (!classInfo) return;
|
|
168
|
+
|
|
169
|
+
markdown += `## ${className}\n\n`;
|
|
170
|
+
|
|
171
|
+
// Add extends info
|
|
172
|
+
if (classInfo.augments && classInfo.augments.length > 0) {
|
|
173
|
+
markdown += `**Extends:** ${classInfo.augments.join(', ')}\n\n`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
markdown += `${classInfo.desc}\n`;
|
|
177
|
+
|
|
178
|
+
// Class-level examples
|
|
179
|
+
if (classInfo.examples.length > 0 && !classInfo.constructor) {
|
|
180
|
+
markdown += formatExamples(classInfo.examples);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Constructor
|
|
184
|
+
if (classInfo.constructor) {
|
|
185
|
+
markdown += `\n### ${className} Constructor\n\n`;
|
|
186
|
+
markdown += `Creates a new ${className} instance.\n`;
|
|
187
|
+
markdown += formatParams(classInfo.constructor.params);
|
|
188
|
+
markdown += formatExamples(classInfo.constructor.examples);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Methods
|
|
192
|
+
classInfo.methods.forEach(method => {
|
|
193
|
+
markdown += `\n### ${className}.${method.name}()\n\n`;
|
|
194
|
+
markdown += `${method.description || ''}\n`;
|
|
195
|
+
markdown += formatParams(method.params);
|
|
196
|
+
markdown += formatReturns(method.returns);
|
|
197
|
+
markdown += formatThrows(method.exceptions);
|
|
198
|
+
markdown += formatExamples(method.examples);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
markdown += `\n---\n\n`;
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Generate function documentation
|
|
205
|
+
markdown += `## Low Level Functions\n\n`;
|
|
206
|
+
markdown += `These functions provide low-level access to OSC encoding and decoding for advanced use cases.\n\n`;
|
|
207
|
+
|
|
208
|
+
functionOrder.forEach(funcName => {
|
|
209
|
+
const func = functions[funcName];
|
|
210
|
+
if (!func) return;
|
|
211
|
+
|
|
212
|
+
markdown += `### ${funcName}()\n\n`;
|
|
213
|
+
markdown += `${func.description || ''}\n`;
|
|
214
|
+
markdown += formatParams(func.params);
|
|
215
|
+
markdown += formatReturns(func.returns);
|
|
216
|
+
markdown += formatThrows(func.exceptions);
|
|
217
|
+
markdown += formatExamples(func.examples);
|
|
218
|
+
markdown += `\n`;
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Write output
|
|
222
|
+
try {
|
|
223
|
+
writeFileSync('docs/API.md', markdown, 'utf8');
|
|
224
|
+
console.log('✅ API documentation generated: docs/API.md');
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error('❌ Failed to write API.md:');
|
|
227
|
+
console.error(error.message);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Test CJS-style TypeScript imports
|
|
2
|
+
import type { Client, Server, Message, Bundle } from 'node-osc';
|
|
3
|
+
const osc = require('node-osc');
|
|
4
|
+
|
|
5
|
+
// Create server first (typical usage pattern)
|
|
6
|
+
const server: Server = new osc.Server(3333, '0.0.0.0');
|
|
7
|
+
|
|
8
|
+
// Create client after server
|
|
9
|
+
const client: Client = new osc.Client('127.0.0.1', 3333);
|
|
10
|
+
|
|
11
|
+
// Test Message type
|
|
12
|
+
const message: Message = new osc.Message('/test', 1, 2, 3);
|
|
13
|
+
|
|
14
|
+
// Test Bundle type
|
|
15
|
+
const bundle: Bundle = new osc.Bundle(['/one', 1]);
|
|
16
|
+
|
|
17
|
+
// Test encode/decode with consistent type annotations
|
|
18
|
+
const encoded: Buffer = osc.encode(message);
|
|
19
|
+
const decoded: Object = osc.decode(encoded);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Test ESM TypeScript imports with Top-Level Await
|
|
2
|
+
import { once } from 'node:events';
|
|
3
|
+
import { Client, Server, Message, Bundle, encode, decode } from 'node-osc';
|
|
4
|
+
|
|
5
|
+
// Create server first (typical usage pattern)
|
|
6
|
+
const server: Server = new Server(3333, '0.0.0.0');
|
|
7
|
+
|
|
8
|
+
// Wait for server to be ready (pattern from examples)
|
|
9
|
+
await once(server, 'listening');
|
|
10
|
+
|
|
11
|
+
server.on('message', (msg) => {
|
|
12
|
+
console.log('Received message:', msg);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Create client after server
|
|
16
|
+
const client: Client = new Client('127.0.0.1', 3333);
|
|
17
|
+
|
|
18
|
+
// Test async usage with Top-Level Await (ESM feature)
|
|
19
|
+
await client.send('/test', 1, 2, 3);
|
|
20
|
+
await client.close();
|
|
21
|
+
await server.close();
|
|
22
|
+
|
|
23
|
+
// Test Message type
|
|
24
|
+
const message: Message = new Message('/oscillator/frequency', 440);
|
|
25
|
+
message.append(3.14);
|
|
26
|
+
message.append('hello');
|
|
27
|
+
message.append(true);
|
|
28
|
+
|
|
29
|
+
// Test Bundle type
|
|
30
|
+
const bundle: Bundle = new Bundle(['/one', 1], ['/two', 2]);
|
|
31
|
+
bundle.append(['/three', 3]);
|
|
32
|
+
|
|
33
|
+
// Test encode/decode with consistent type annotations
|
|
34
|
+
const encoded: Buffer = encode(message);
|
|
35
|
+
const decoded: Object = decode(encoded);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"noEmit": true,
|
|
4
|
+
"skipLibCheck": true,
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"target": "ES2022",
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"baseUrl": ".",
|
|
10
|
+
"paths": {
|
|
11
|
+
"node-osc": ["../../../types/index.d.mts"]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"include": [
|
|
15
|
+
"test-cjs-types.ts"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"noEmit": true,
|
|
4
|
+
"skipLibCheck": true,
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"module": "ES2022",
|
|
7
|
+
"target": "ES2022",
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"baseUrl": ".",
|
|
10
|
+
"paths": {
|
|
11
|
+
"node-osc": ["../../../types/index.d.mts"]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"include": [
|
|
15
|
+
"test-esm-types.ts"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/test/test-bundle.mjs
CHANGED
package/test/test-client.mjs
CHANGED
|
@@ -106,3 +106,155 @@ test('client: failure', (t) => {
|
|
|
106
106
|
t.equal(err.code, 'ERR_SOCKET_DGRAM_NOT_RUNNING');
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
|
+
|
|
110
|
+
test('client: close with callback', (t) => {
|
|
111
|
+
const client = new Client('127.0.0.1', t.context.port);
|
|
112
|
+
|
|
113
|
+
t.plan(1);
|
|
114
|
+
|
|
115
|
+
client.close((err) => {
|
|
116
|
+
t.error(err, 'close should not error');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('client: send bundle with non-numeric timetag', (t) => {
|
|
121
|
+
const oscServer = new Server(t.context.port, '127.0.0.1');
|
|
122
|
+
const client = new Client('127.0.0.1', t.context.port);
|
|
123
|
+
|
|
124
|
+
t.plan(2);
|
|
125
|
+
|
|
126
|
+
oscServer.on('bundle', (bundle) => {
|
|
127
|
+
oscServer.close();
|
|
128
|
+
t.equal(bundle.timetag, 0, 'should receive immediate execution timetag as 0');
|
|
129
|
+
t.ok(bundle.elements.length > 0, 'should have elements');
|
|
130
|
+
client.close();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Send bundle with non-numeric timetag (will be encoded as immediate execution)
|
|
134
|
+
const bundle = {
|
|
135
|
+
oscType: 'bundle',
|
|
136
|
+
timetag: 'immediate', // Non-numeric, will trigger the else branch in writeTimeTag
|
|
137
|
+
elements: [
|
|
138
|
+
{
|
|
139
|
+
oscType: 'message',
|
|
140
|
+
address: '/test1',
|
|
141
|
+
args: [{ type: 'i', value: 42 }]
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
client.send(bundle);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('client: send bundle with null timetag', (t) => {
|
|
150
|
+
const oscServer = new Server(t.context.port, '127.0.0.1');
|
|
151
|
+
const client = new Client('127.0.0.1', t.context.port);
|
|
152
|
+
|
|
153
|
+
t.plan(2);
|
|
154
|
+
|
|
155
|
+
oscServer.on('bundle', (bundle) => {
|
|
156
|
+
oscServer.close();
|
|
157
|
+
t.equal(bundle.timetag, 0, 'should receive immediate execution timetag as 0');
|
|
158
|
+
t.ok(bundle.elements.length > 0, 'should have elements');
|
|
159
|
+
client.close();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Send bundle with null timetag (will be encoded as immediate execution)
|
|
163
|
+
const bundle = {
|
|
164
|
+
oscType: 'bundle',
|
|
165
|
+
timetag: null, // Null, will trigger the else branch in writeTimeTag
|
|
166
|
+
elements: [
|
|
167
|
+
{
|
|
168
|
+
oscType: 'message',
|
|
169
|
+
address: '/test2',
|
|
170
|
+
args: [{ type: 's', value: 'hello' }]
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
client.send(bundle);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('client: send message with float type arg', (t) => {
|
|
179
|
+
const oscServer = new Server(t.context.port, '127.0.0.1');
|
|
180
|
+
const client = new Client('127.0.0.1', t.context.port);
|
|
181
|
+
|
|
182
|
+
t.plan(2);
|
|
183
|
+
|
|
184
|
+
oscServer.on('message', (msg) => {
|
|
185
|
+
oscServer.close();
|
|
186
|
+
t.equal(msg[0], '/float-test', 'should receive address');
|
|
187
|
+
t.ok(Math.abs(msg[1] - 9.876) < 0.001, 'should receive float value');
|
|
188
|
+
client.close();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Send raw message with 'float' type to hit that case label
|
|
192
|
+
client.send({
|
|
193
|
+
oscType: 'message',
|
|
194
|
+
address: '/float-test',
|
|
195
|
+
args: [{ type: 'float', value: 9.876 }]
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('client: send message with blob type arg', (t) => {
|
|
200
|
+
const oscServer = new Server(t.context.port, '127.0.0.1');
|
|
201
|
+
const client = new Client('127.0.0.1', t.context.port);
|
|
202
|
+
|
|
203
|
+
t.plan(2);
|
|
204
|
+
|
|
205
|
+
oscServer.on('message', (msg) => {
|
|
206
|
+
oscServer.close();
|
|
207
|
+
t.equal(msg[0], '/blob-test', 'should receive address');
|
|
208
|
+
t.ok(Buffer.isBuffer(msg[1]), 'should receive blob as buffer');
|
|
209
|
+
client.close();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Send raw message with 'blob' type to hit that case label
|
|
213
|
+
client.send({
|
|
214
|
+
oscType: 'message',
|
|
215
|
+
address: '/blob-test',
|
|
216
|
+
args: [{ type: 'blob', value: Buffer.from([0xAA, 0xBB]) }]
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test('client: send message with double type arg', (t) => {
|
|
221
|
+
const oscServer = new Server(t.context.port, '127.0.0.1');
|
|
222
|
+
const client = new Client('127.0.0.1', t.context.port);
|
|
223
|
+
|
|
224
|
+
t.plan(2);
|
|
225
|
+
|
|
226
|
+
oscServer.on('message', (msg) => {
|
|
227
|
+
oscServer.close();
|
|
228
|
+
t.equal(msg[0], '/double-test', 'should receive address');
|
|
229
|
+
t.ok(Math.abs(msg[1] - 1.23456789) < 0.001, 'should receive double value as float');
|
|
230
|
+
client.close();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Send raw message with 'double' type to hit that case label
|
|
234
|
+
client.send({
|
|
235
|
+
oscType: 'message',
|
|
236
|
+
address: '/double-test',
|
|
237
|
+
args: [{ type: 'double', value: 1.23456789 }]
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('client: send message with midi type arg', (t) => {
|
|
242
|
+
const oscServer = new Server(t.context.port, '127.0.0.1');
|
|
243
|
+
const client = new Client('127.0.0.1', t.context.port);
|
|
244
|
+
|
|
245
|
+
t.plan(2);
|
|
246
|
+
|
|
247
|
+
oscServer.on('message', (msg) => {
|
|
248
|
+
oscServer.close();
|
|
249
|
+
t.equal(msg[0], '/midi-test', 'should receive address');
|
|
250
|
+
t.ok(Buffer.isBuffer(msg[1]), 'should receive MIDI as buffer');
|
|
251
|
+
client.close();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Send raw message with 'midi' type to hit that case label
|
|
255
|
+
client.send({
|
|
256
|
+
oscType: 'message',
|
|
257
|
+
address: '/midi-test',
|
|
258
|
+
args: [{ type: 'midi', value: Buffer.from([0x00, 0x90, 0x40, 0x60]) }]
|
|
259
|
+
});
|
|
260
|
+
});
|
package/test/test-e2e.mjs
CHANGED
|
@@ -22,9 +22,12 @@ test('osc: argument message no callback', (t) => {
|
|
|
22
22
|
|
|
23
23
|
t.plan(1);
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
t.teardown(() => {
|
|
26
26
|
oscServer.close();
|
|
27
27
|
client.close();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
oscServer.on('message', (msg) => {
|
|
28
31
|
t.same(msg, ['/test', 1, 2, 'testing'], 'We should receive expected payload');
|
|
29
32
|
});
|
|
30
33
|
|
|
@@ -39,13 +42,16 @@ test('osc: client with callback and message as arguments', (t) => {
|
|
|
39
42
|
|
|
40
43
|
t.plan(2);
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
t.teardown(() => {
|
|
43
46
|
oscServer.close();
|
|
47
|
+
client.close();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
oscServer.on('message', (msg) => {
|
|
44
51
|
t.same(msg, ['/test', 1, 2, 'testing'], 'We should receive expected payload');
|
|
45
52
|
});
|
|
46
53
|
|
|
47
54
|
client.send('/test', 1, 2, 'testing', (err) => {
|
|
48
55
|
t.error(err, 'there should be no error');
|
|
49
|
-
client.close();
|
|
50
56
|
});
|
|
51
57
|
});
|