buttplug 3.2.2 → 4.0.1

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 (179) hide show
  1. package/.eslintrc.js +25 -25
  2. package/.jscsrc +2 -2
  3. package/.jshintrc +5 -5
  4. package/.prettierrc.json +3 -3
  5. package/.yarnrc.yml +5 -5
  6. package/CHANGELOG.md +591 -577
  7. package/LICENSE +27 -27
  8. package/README.md +105 -97
  9. package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js +6 -9
  10. package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js.map +1 -1
  11. package/dist/main/src/client/{Client.d.ts → ButtplugClient.d.ts} +3 -4
  12. package/dist/main/src/client/ButtplugClient.js +232 -0
  13. package/dist/main/src/client/ButtplugClient.js.map +1 -0
  14. package/dist/main/src/client/ButtplugClientConnectorException.js +17 -7
  15. package/dist/main/src/client/ButtplugClientConnectorException.js.map +1 -1
  16. package/dist/main/src/client/ButtplugClientDevice.d.ts +13 -28
  17. package/dist/main/src/client/ButtplugClientDevice.js +105 -247
  18. package/dist/main/src/client/ButtplugClientDevice.js.map +1 -1
  19. package/dist/main/src/client/ButtplugClientDeviceCommand.d.ts +42 -0
  20. package/dist/main/src/client/ButtplugClientDeviceCommand.js +105 -0
  21. package/dist/main/src/client/ButtplugClientDeviceCommand.js.map +1 -0
  22. package/dist/main/src/client/ButtplugClientDeviceFeature.d.ts +18 -0
  23. package/dist/main/src/client/ButtplugClientDeviceFeature.js +166 -0
  24. package/dist/main/src/client/ButtplugClientDeviceFeature.js.map +1 -0
  25. package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -8
  26. package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js +1 -4
  27. package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js.map +1 -1
  28. package/dist/main/src/core/Exceptions.js +27 -9
  29. package/dist/main/src/core/Exceptions.js.map +1 -1
  30. package/dist/main/src/core/Logging.js +12 -6
  31. package/dist/main/src/core/Logging.js.map +1 -1
  32. package/dist/main/src/core/Messages.d.ts +119 -230
  33. package/dist/main/src/core/Messages.js +50 -404
  34. package/dist/main/src/core/Messages.js.map +1 -1
  35. package/dist/main/src/index.d.ts +2 -2
  36. package/dist/main/src/index.js +4 -2
  37. package/dist/main/src/index.js.map +1 -1
  38. package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js +40 -52
  39. package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js.map +1 -1
  40. package/dist/main/src/utils/ButtplugMessageSorter.js +27 -15
  41. package/dist/main/src/utils/ButtplugMessageSorter.js.map +1 -1
  42. package/dist/main/src/utils/Utils.js +1 -2
  43. package/dist/main/src/utils/Utils.js.map +1 -1
  44. package/dist/web/buttplug.js +1 -38
  45. package/dist/web/buttplug.mjs +595 -1984
  46. package/dist/web/client/ButtplugBrowserWebsocketClientConnector.d.ts +0 -7
  47. package/dist/web/client/{Client.d.ts → ButtplugClient.d.ts} +3 -11
  48. package/dist/web/client/ButtplugClientConnectorException.d.ts +0 -7
  49. package/dist/web/client/ButtplugClientDevice.d.ts +14 -29
  50. package/dist/web/client/ButtplugClientDeviceCommand.d.ts +42 -0
  51. package/dist/web/client/ButtplugClientDeviceFeature.d.ts +18 -0
  52. package/dist/web/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -15
  53. package/dist/web/client/IButtplugClientConnector.d.ts +0 -7
  54. package/dist/web/core/Exceptions.d.ts +1 -1
  55. package/dist/web/core/Logging.d.ts +0 -7
  56. package/dist/web/core/Messages.d.ts +119 -229
  57. package/dist/web/index.d.ts +2 -2
  58. package/dist/web/utils/ButtplugBrowserWebsocketConnector.d.ts +0 -7
  59. package/examples/node/SYNC_MANIFEST.md +105 -0
  60. package/examples/node/application-example.ts +213 -0
  61. package/examples/node/async-example.ts +124 -0
  62. package/examples/node/connection-example.ts +76 -0
  63. package/examples/node/device-control-example.ts +131 -0
  64. package/examples/node/device-enumeration-example.ts +86 -0
  65. package/examples/node/device-info-example.ts +131 -0
  66. package/examples/node/errors-example.ts +166 -0
  67. package/examples/node/package-lock.json +281 -0
  68. package/examples/node/package.json +25 -0
  69. package/examples/node/remote-connector-example.ts +84 -0
  70. package/examples/node/tsconfig.json +14 -0
  71. package/examples/web/application-example.js +197 -0
  72. package/examples/web/async-example.js +90 -0
  73. package/examples/web/device-control-example.js +87 -0
  74. package/examples/web/device-enumeration-example.js +49 -0
  75. package/examples/web/device-info-example.js +100 -0
  76. package/examples/web/errors-example.js +110 -0
  77. package/examples/web/index.html +55 -0
  78. package/examples/web/logging.js +42 -0
  79. package/examples/web/ping-timeout-example.js +59 -0
  80. package/examples/web/remote-connector-example.js +68 -0
  81. package/node-test.js +24 -0
  82. package/node-test.ts +23 -5
  83. package/package.json +85 -87
  84. package/src/client/ButtplugBrowserWebsocketClientConnector.ts +25 -25
  85. package/src/client/ButtplugClient.ts +242 -0
  86. package/src/client/ButtplugClientConnectorException.ts +16 -16
  87. package/src/client/ButtplugClientDevice.ts +178 -401
  88. package/src/client/ButtplugClientDeviceCommand.ts +112 -0
  89. package/src/client/ButtplugClientDeviceFeature.ts +138 -0
  90. package/src/client/ButtplugNodeWebsocketClientConnector.ts +17 -17
  91. package/src/client/IButtplugClientConnector.ts +18 -18
  92. package/src/core/Exceptions.ts +107 -101
  93. package/src/core/Logging.ts +197 -197
  94. package/src/core/Messages.ts +205 -480
  95. package/src/core/index.d.ts +4 -4
  96. package/src/index.ts +21 -19
  97. package/src/utils/ButtplugBrowserWebsocketConnector.ts +89 -89
  98. package/src/utils/ButtplugMessageSorter.ts +66 -65
  99. package/src/utils/Utils.ts +3 -3
  100. package/tsconfig.json +22 -22
  101. package/tsfmt.json +14 -14
  102. package/tslint.json +27 -27
  103. package/typedocconfig.js +6 -6
  104. package/vite.config.ts +26 -26
  105. package/dist/main/src/client/Client.js +0 -242
  106. package/dist/main/src/client/Client.js.map +0 -1
  107. package/dist/main/src/core/MessageUtils.d.ts +0 -10
  108. package/dist/main/src/core/MessageUtils.js +0 -65
  109. package/dist/main/src/core/MessageUtils.js.map +0 -1
  110. package/dist/web/core/MessageUtils.d.ts +0 -10
  111. package/doc/.nojekyll +0 -1
  112. package/doc/assets/highlight.css +0 -22
  113. package/doc/assets/main.js +0 -58
  114. package/doc/assets/search.js +0 -1
  115. package/doc/assets/style.css +0 -1280
  116. package/doc/classes/ButtplugBrowserWebsocketClientConnector.html +0 -234
  117. package/doc/classes/ButtplugClient.html +0 -331
  118. package/doc/classes/ButtplugClientConnectorException.html +0 -216
  119. package/doc/classes/ButtplugClientDevice.html +0 -489
  120. package/doc/classes/ButtplugDeviceError.html +0 -218
  121. package/doc/classes/ButtplugDeviceMessage.html +0 -165
  122. package/doc/classes/ButtplugError.html +0 -220
  123. package/doc/classes/ButtplugInitError.html +0 -218
  124. package/doc/classes/ButtplugLogger.html +0 -288
  125. package/doc/classes/ButtplugMessage.html +0 -147
  126. package/doc/classes/ButtplugMessageError.html +0 -218
  127. package/doc/classes/ButtplugMessageSorter.html +0 -128
  128. package/doc/classes/ButtplugNodeWebsocketClientConnector.html +0 -239
  129. package/doc/classes/ButtplugPingError.html +0 -218
  130. package/doc/classes/ButtplugSystemMessage.html +0 -150
  131. package/doc/classes/ButtplugUnknownError.html +0 -218
  132. package/doc/classes/DeviceAdded.html +0 -186
  133. package/doc/classes/DeviceInfo.html +0 -114
  134. package/doc/classes/DeviceList.html +0 -160
  135. package/doc/classes/DeviceRemoved.html +0 -158
  136. package/doc/classes/Error.html +0 -179
  137. package/doc/classes/GenericDeviceMessageAttributes.html +0 -107
  138. package/doc/classes/GenericMessageSubcommand.html +0 -90
  139. package/doc/classes/LinearCmd.html +0 -187
  140. package/doc/classes/LogMessage.html +0 -134
  141. package/doc/classes/MessageAttributes.html +0 -160
  142. package/doc/classes/Ok.html +0 -151
  143. package/doc/classes/Ping.html +0 -151
  144. package/doc/classes/RawDeviceMessageAttributes.html +0 -86
  145. package/doc/classes/RawReadCmd.html +0 -188
  146. package/doc/classes/RawReading.html +0 -179
  147. package/doc/classes/RawSubscribeCmd.html +0 -170
  148. package/doc/classes/RawUnsubscribeCmd.html +0 -170
  149. package/doc/classes/RawWriteCmd.html +0 -188
  150. package/doc/classes/RequestDeviceList.html +0 -151
  151. package/doc/classes/RequestServerInfo.html +0 -169
  152. package/doc/classes/RotateCmd.html +0 -187
  153. package/doc/classes/RotateSubcommand.html +0 -108
  154. package/doc/classes/ScalarCmd.html +0 -170
  155. package/doc/classes/ScalarSubcommand.html +0 -108
  156. package/doc/classes/ScanningFinished.html +0 -146
  157. package/doc/classes/SensorDeviceMessageAttributes.html +0 -107
  158. package/doc/classes/SensorReadCmd.html +0 -179
  159. package/doc/classes/SensorReading.html +0 -188
  160. package/doc/classes/ServerInfo.html +0 -178
  161. package/doc/classes/StartScanning.html +0 -151
  162. package/doc/classes/StopAllDevices.html +0 -151
  163. package/doc/classes/StopDeviceCmd.html +0 -161
  164. package/doc/classes/StopScanning.html +0 -151
  165. package/doc/classes/VectorSubcommand.html +0 -108
  166. package/doc/enums/ActuatorType.html +0 -104
  167. package/doc/enums/ButtplugLogLevel.html +0 -97
  168. package/doc/enums/ErrorClass.html +0 -90
  169. package/doc/enums/SensorType.html +0 -90
  170. package/doc/functions/FromJSON.html +0 -113
  171. package/doc/index.html +0 -184
  172. package/doc/interfaces/IButtplugClientConnector.html +0 -137
  173. package/doc/modules.html +0 -176
  174. package/doc/variables/DEFAULT_MESSAGE_ID.html +0 -104
  175. package/doc/variables/MAX_ID.html +0 -104
  176. package/doc/variables/MESSAGE_SPEC_VERSION.html +0 -104
  177. package/doc/variables/SYSTEM_MESSAGE_ID.html +0 -104
  178. package/src/client/Client.ts +0 -276
  179. package/src/core/MessageUtils.ts +0 -48
@@ -1,10 +1,3 @@
1
- /*!
2
- * Buttplug JS Source Code File - Visit https://buttplug.io for more info about
3
- * the project. Licensed under the BSD 3-Clause license. See LICENSE file in the
4
- * project root for full license information.
5
- *
6
- * @copyright Copyright (c) Nonpolynomial Labs LLC. All rights reserved.
7
- */
8
1
  import { EventEmitter } from 'eventemitter3';
9
2
  import { ButtplugMessage } from '../core/Messages';
10
3
  export declare class ButtplugBrowserWebsocketConnector extends EventEmitter {
@@ -0,0 +1,105 @@
1
+ # Buttplug TypeScript/JavaScript Examples
2
+
3
+ These examples demonstrate how to use the Buttplug TypeScript/JavaScript library for Node.js CLI applications.
4
+
5
+ ## Prerequisites
6
+
7
+ 1. Install [Intiface Central](https://intiface.com/central)
8
+ 2. Start the server in Intiface Central
9
+ 3. Install dependencies: `npm install`
10
+
11
+ ## Running Examples
12
+
13
+ Each example can be run with ts-node:
14
+
15
+ ```bash
16
+ npx ts-node --esm <example-name>.ts
17
+ ```
18
+
19
+ Or use the npm scripts:
20
+
21
+ ```bash
22
+ npm run connection # Basic connection example
23
+ npm run device-enumeration # Device scanning and events
24
+ npm run device-control # Sending commands to devices
25
+ npm run device-info # Device feature introspection
26
+ npm run async # Async/await patterns
27
+ npm run errors # Error handling patterns
28
+ npm run remote-connector # Explicit connector setup
29
+ npm run application # Complete interactive demo
30
+ ```
31
+
32
+ ## Examples
33
+
34
+ | File | Description |
35
+ |------|-------------|
36
+ | `connection-example.ts` | Basic WebSocket connection and error handling |
37
+ | `device-enumeration-example.ts` | Device scanning and event listening |
38
+ | `device-control-example.ts` | Sending commands and capability queries |
39
+ | `device-info-example.ts` | Device feature introspection |
40
+ | `async-example.ts` | Async/await patterns and event handling |
41
+ | `errors-example.ts` | Error type reference and handling patterns |
42
+ | `remote-connector-example.ts` | Explicit connector setup |
43
+ | `application-example.ts` | Complete interactive CLI demo |
44
+
45
+ ## Key API Patterns
46
+
47
+ ### Connection
48
+
49
+ ```typescript
50
+ import {
51
+ ButtplugClient,
52
+ ButtplugNodeWebsocketClientConnector,
53
+ } from 'buttplug';
54
+
55
+ const client = new ButtplugClient('App Name');
56
+ const connector = new ButtplugNodeWebsocketClientConnector('ws://127.0.0.1:12345');
57
+ await client.connect(connector);
58
+ ```
59
+
60
+ ### Events
61
+
62
+ ```typescript
63
+ client.addListener('deviceadded', (device) => {
64
+ console.log(`Device connected: ${device.name}`);
65
+ });
66
+
67
+ client.addListener('deviceremoved', (device) => {
68
+ console.log(`Device disconnected: ${device.name}`);
69
+ });
70
+ ```
71
+
72
+ ### Device Control
73
+
74
+ ```typescript
75
+ import { DeviceOutput, OutputType, InputType } from 'buttplug';
76
+
77
+ // Check capabilities
78
+ if (device.hasOutput(OutputType.Vibrate)) {
79
+ // Send command using the fluent builder API
80
+ await device.runOutput(DeviceOutput.Vibrate.percent(0.5));
81
+ }
82
+
83
+ // Stop the device
84
+ await device.stop();
85
+
86
+ // Read battery level
87
+ if (device.hasInput(InputType.Battery)) {
88
+ const battery = await device.battery();
89
+ console.log(`Battery: ${battery * 100}%`);
90
+ }
91
+ ```
92
+
93
+ ## Node.js vs Browser
94
+
95
+ - **Node.js**: Use `ButtplugNodeWebsocketClientConnector` (requires `ws` package)
96
+ - **Browser**: Use `ButtplugBrowserWebsocketClientConnector` (uses native WebSocket)
97
+
98
+ ## Syncing to Documentation
99
+
100
+ These examples are synced to the Buttplug documentation site using the sync script in docs.buttplug.io:
101
+
102
+ ```bash
103
+ cd ../docs.buttplug.io
104
+ ./scripts/sync-examples.sh
105
+ ```
@@ -0,0 +1,213 @@
1
+ // Buttplug TypeScript - Complete Application Example
2
+ //
3
+ // This is a complete, working example that demonstrates the full workflow
4
+ // of a Buttplug application. If you're new to Buttplug, start here!
5
+ //
6
+ // Prerequisites:
7
+ // 1. Install Intiface Central: https://intiface.com/central
8
+ // 2. Start the server in Intiface Central (click "Start Server")
9
+ // 3. Run: npx ts-node --esm application-example.ts
10
+
11
+ import {
12
+ ButtplugClient,
13
+ ButtplugNodeWebsocketClientConnector,
14
+ ButtplugClientDevice,
15
+ ButtplugClientConnectorException,
16
+ ButtplugDeviceError,
17
+ ButtplugError,
18
+ DeviceOutput,
19
+ OutputType,
20
+ InputType,
21
+ } from 'buttplug';
22
+ import * as readline from 'readline';
23
+
24
+ function createReadlineInterface(): readline.Interface {
25
+ return readline.createInterface({
26
+ input: process.stdin,
27
+ output: process.stdout,
28
+ });
29
+ }
30
+
31
+ async function waitForEnter(prompt: string): Promise<void> {
32
+ const rl = createReadlineInterface();
33
+ return new Promise((resolve) => {
34
+ rl.question(prompt, () => {
35
+ rl.close();
36
+ resolve();
37
+ });
38
+ });
39
+ }
40
+
41
+ async function prompt(question: string): Promise<string> {
42
+ const rl = createReadlineInterface();
43
+ return new Promise((resolve) => {
44
+ rl.question(question, (answer) => {
45
+ rl.close();
46
+ resolve(answer);
47
+ });
48
+ });
49
+ }
50
+
51
+ async function main(): Promise<void> {
52
+ console.log('===========================================');
53
+ console.log(' Buttplug TypeScript Application Example');
54
+ console.log('===========================================\n');
55
+
56
+ // Step 1: Create a client
57
+ // The client name identifies your application to the server.
58
+ const client = new ButtplugClient('My Buttplug Application');
59
+
60
+ // Step 2: Set up event handlers
61
+ // Always do this BEFORE connecting to avoid missing events.
62
+ client.addListener('deviceadded', (device: ButtplugClientDevice) => {
63
+ console.log(`[+] Device connected: ${device.name}`);
64
+ });
65
+
66
+ client.addListener('deviceremoved', (device: ButtplugClientDevice) => {
67
+ console.log(`[-] Device disconnected: ${device.name}`);
68
+ });
69
+
70
+ client.addListener('disconnect', () => {
71
+ console.log('[!] Server connection lost!');
72
+ });
73
+
74
+ // Step 3: Connect to the server
75
+ console.log('Connecting to Intiface Central...');
76
+ try {
77
+ const connector = new ButtplugNodeWebsocketClientConnector(
78
+ 'ws://127.0.0.1:12345'
79
+ );
80
+ await client.connect(connector);
81
+ } catch (e) {
82
+ if (e instanceof ButtplugClientConnectorException) {
83
+ console.log('ERROR: Could not connect to Intiface Central!');
84
+ console.log(
85
+ 'Make sure Intiface Central is running and the server is started.'
86
+ );
87
+ console.log('Default address: ws://127.0.0.1:12345');
88
+ return;
89
+ }
90
+ throw e;
91
+ }
92
+ console.log('Connected!\n');
93
+
94
+ // Step 4: Scan for devices
95
+ console.log('Scanning for devices...');
96
+ console.log('Turn on your Bluetooth/USB devices now.\n');
97
+ await client.startScanning();
98
+
99
+ // Wait for devices
100
+ await waitForEnter('Press Enter when your devices are connected...');
101
+ await client.stopScanning();
102
+
103
+ // Step 5: Check what devices we found
104
+ const devices = Array.from(client.devices.values());
105
+ if (devices.length === 0) {
106
+ console.log('No devices found. Make sure your device is:');
107
+ console.log(' - Turned on');
108
+ console.log(' - In pairing/discoverable mode');
109
+ console.log(' - Supported by Buttplug (check https://iostindex.com)');
110
+ await client.disconnect();
111
+ return;
112
+ }
113
+
114
+ console.log(`\nFound ${devices.length} device(s):\n`);
115
+
116
+ // Step 6: Display device capabilities
117
+ for (const device of devices) {
118
+ console.log(` ${device.name}`);
119
+
120
+ // Check output capabilities (things we can make the device do)
121
+ const outputs: string[] = [];
122
+ if (device.hasOutput(OutputType.Vibrate)) outputs.push('Vibrate');
123
+ if (device.hasOutput(OutputType.Rotate)) outputs.push('Rotate');
124
+ if (device.hasOutput(OutputType.Oscillate)) outputs.push('Oscillate');
125
+ if (device.hasOutput(OutputType.Position)) outputs.push('Position');
126
+ if (device.hasOutput(OutputType.Constrict)) outputs.push('Constrict');
127
+
128
+ if (outputs.length > 0) {
129
+ console.log(` Outputs: ${outputs.join(', ')}`);
130
+ }
131
+
132
+ // Check input capabilities (sensors we can read)
133
+ const inputs: string[] = [];
134
+ if (device.hasInput(InputType.Battery)) inputs.push('Battery');
135
+ if (device.hasInput(InputType.RSSI)) inputs.push('RSSI');
136
+ if (device.hasInput(InputType.Button)) inputs.push('Button');
137
+ if (device.hasInput(InputType.Pressure)) inputs.push('Pressure');
138
+
139
+ if (inputs.length > 0) {
140
+ console.log(` Inputs: ${inputs.join(', ')}`);
141
+ }
142
+
143
+ console.log();
144
+ }
145
+
146
+ // Step 7: Interactive device control
147
+ console.log('=== Interactive Control ===');
148
+ console.log('Commands:');
149
+ console.log(' v <0-100> - Vibrate all devices at percentage');
150
+ console.log(' s - Stop all devices');
151
+ console.log(' b - Read battery levels');
152
+ console.log(' q - Quit\n');
153
+
154
+ let running = true;
155
+ while (running) {
156
+ const input = (await prompt('> ')).trim().toLowerCase();
157
+
158
+ if (!input) continue;
159
+
160
+ try {
161
+ if (input.startsWith('v ')) {
162
+ // Vibrate command
163
+ const percentStr = input.slice(2);
164
+ const percent = parseInt(percentStr, 10);
165
+ if (!isNaN(percent) && percent >= 0 && percent <= 100) {
166
+ const intensity = percent / 100.0;
167
+ for (const device of devices) {
168
+ if (device.hasOutput(OutputType.Vibrate)) {
169
+ await device.runOutput(DeviceOutput.Vibrate.percent(intensity));
170
+ console.log(` ${device.name}: vibrating at ${percent}%`);
171
+ }
172
+ }
173
+ } else {
174
+ console.log(' Usage: v <0-100>');
175
+ }
176
+ } else if (input === 's') {
177
+ // Stop all devices
178
+ await client.stopAllDevices();
179
+ console.log(' All devices stopped.');
180
+ } else if (input === 'b') {
181
+ // Read battery levels
182
+ for (const device of devices) {
183
+ if (device.hasInput(InputType.Battery)) {
184
+ const battery = await device.battery();
185
+ console.log(` ${device.name}: ${(battery * 100).toFixed(0)}% battery`);
186
+ } else {
187
+ console.log(` ${device.name}: no battery sensor`);
188
+ }
189
+ }
190
+ } else if (input === 'q') {
191
+ running = false;
192
+ } else {
193
+ console.log(' Unknown command. Use v, s, b, or q.');
194
+ }
195
+ } catch (e) {
196
+ if (e instanceof ButtplugDeviceError) {
197
+ console.log(` Device error: ${e.message}`);
198
+ } else if (e instanceof ButtplugError) {
199
+ console.log(` Error: ${e.message}`);
200
+ } else {
201
+ throw e;
202
+ }
203
+ }
204
+ }
205
+
206
+ // Step 8: Clean up
207
+ console.log('\nStopping devices and disconnecting...');
208
+ await client.stopAllDevices();
209
+ await client.disconnect();
210
+ console.log('Goodbye!');
211
+ }
212
+
213
+ main().catch(console.error);
@@ -0,0 +1,124 @@
1
+ // Buttplug TypeScript - Async Patterns Example
2
+ //
3
+ // This example demonstrates async/await patterns and event handling
4
+ // in the Buttplug library. The library is fully async - all operations
5
+ // that might block (network, device communication) use async/await.
6
+ //
7
+ // Prerequisites:
8
+ // 1. Install Intiface Central: https://intiface.com/central
9
+ // 2. Start the server in Intiface Central
10
+ // 3. Run: npx ts-node --esm async-example.ts
11
+
12
+ import {
13
+ ButtplugClient,
14
+ ButtplugNodeWebsocketClientConnector,
15
+ ButtplugClientDevice,
16
+ DeviceOutput,
17
+ OutputType,
18
+ } from 'buttplug';
19
+ import * as readline from 'readline';
20
+
21
+ async function waitForEnter(prompt: string): Promise<void> {
22
+ const rl = readline.createInterface({
23
+ input: process.stdin,
24
+ output: process.stdout,
25
+ });
26
+ return new Promise((resolve) => {
27
+ rl.question(prompt, () => {
28
+ rl.close();
29
+ resolve();
30
+ });
31
+ });
32
+ }
33
+
34
+ function delay(ms: number): Promise<void> {
35
+ return new Promise((resolve) => setTimeout(resolve, ms));
36
+ }
37
+
38
+ async function main(): Promise<void> {
39
+ const client = new ButtplugClient('Async Example');
40
+
41
+ // Events in buttplug-js use EventEmitter3.
42
+ // You can use addListener or on to subscribe to events.
43
+
44
+ // 'deviceadded' is fired when a new device connects
45
+ client.addListener('deviceadded', async (device: ButtplugClientDevice) => {
46
+ // Note: Event handlers can be async!
47
+ console.log(`[Event] Device added: ${device.name}`);
48
+
49
+ // You can interact with the device in the event handler
50
+ if (device.hasOutput(OutputType.Vibrate)) {
51
+ console.log(' Sending welcome vibration...');
52
+ await device.runOutput(DeviceOutput.Vibrate.percent(0.25));
53
+ await delay(200);
54
+ await device.stop();
55
+ }
56
+ });
57
+
58
+ // 'deviceremoved' is fired when a device disconnects
59
+ client.addListener('deviceremoved', (device: ButtplugClientDevice) => {
60
+ console.log(`[Event] Device removed: ${device.name}`);
61
+ });
62
+
63
+ // 'scanningfinished' is fired when scanning completes
64
+ // (some protocols scan continuously until stopped)
65
+ client.addListener('scanningfinished', () => {
66
+ console.log('[Event] Scanning finished');
67
+ });
68
+
69
+ // 'disconnect' is fired when the server connection drops
70
+ client.addListener('disconnect', () => {
71
+ console.log('[Event] Server disconnected!');
72
+ });
73
+
74
+ // 'inputreading' is fired when subscribed sensor data arrives
75
+ client.addListener('inputreading', (reading: unknown) => {
76
+ console.log(`[Event] Input reading: ${JSON.stringify(reading)}`);
77
+ });
78
+
79
+ // Connect asynchronously - this may take time due to network
80
+ console.log('Connecting to server...');
81
+ const connector = new ButtplugNodeWebsocketClientConnector(
82
+ 'ws://127.0.0.1:12345'
83
+ );
84
+ await client.connect(connector);
85
+ console.log('Connected!\n');
86
+
87
+ // Scanning is also async - we start it and wait for events
88
+ console.log('Starting scan. Turn on devices now...');
89
+ console.log('(Events will be printed as devices connect)\n');
90
+ await client.startScanning();
91
+
92
+ // Wait for user input
93
+ await waitForEnter('Press Enter to stop scanning...');
94
+ await client.stopScanning();
95
+
96
+ // Demonstrate concurrent operations
97
+ console.log('\nDemonstrating concurrent device control...');
98
+ const devices = Array.from(client.devices.values());
99
+
100
+ if (devices.length > 0) {
101
+ // Send commands to all devices concurrently
102
+ const tasks = devices
103
+ .filter((d) => d.hasOutput(OutputType.Vibrate))
104
+ .map(async (device) => {
105
+ console.log(` Vibrating ${device.name}...`);
106
+ await device.runOutput(DeviceOutput.Vibrate.percent(0.5));
107
+ await delay(500);
108
+ await device.stop();
109
+ console.log(` ${device.name} stopped.`);
110
+ });
111
+
112
+ // Wait for all commands to complete
113
+ await Promise.all(tasks);
114
+ console.log('All devices stopped.');
115
+ } else {
116
+ console.log('No devices connected.');
117
+ }
118
+
119
+ await waitForEnter('\nPress Enter to disconnect...');
120
+ await client.disconnect();
121
+ console.log('Disconnected.');
122
+ }
123
+
124
+ main().catch(console.error);
@@ -0,0 +1,76 @@
1
+ // Buttplug TypeScript - Connection Example
2
+ //
3
+ // This example demonstrates how to connect to a Buttplug server
4
+ // (like Intiface Central) and handle connection errors.
5
+ //
6
+ // Prerequisites:
7
+ // 1. Install Intiface Central: https://intiface.com/central
8
+ // 2. Start the server in Intiface Central
9
+ // 3. Run: npx ts-node --esm connection-example.ts
10
+
11
+ import {
12
+ ButtplugClient,
13
+ ButtplugNodeWebsocketClientConnector,
14
+ ButtplugClientConnectorException,
15
+ ButtplugError,
16
+ ButtplugInitError,
17
+ } from 'buttplug';
18
+ import * as readline from 'readline';
19
+
20
+ async function waitForEnter(prompt: string): Promise<void> {
21
+ const rl = readline.createInterface({
22
+ input: process.stdin,
23
+ output: process.stdout,
24
+ });
25
+ return new Promise((resolve) => {
26
+ rl.question(prompt, () => {
27
+ rl.close();
28
+ resolve();
29
+ });
30
+ });
31
+ }
32
+
33
+ async function main(): Promise<void> {
34
+ // Create a client with your application's name.
35
+ // This name will be shown in Intiface Central.
36
+ const client = new ButtplugClient('Connection Example');
37
+
38
+ try {
39
+ // Create a connector to the server. Default port for Intiface Central is 12345.
40
+ const connector = new ButtplugNodeWebsocketClientConnector(
41
+ 'ws://127.0.0.1:12345'
42
+ );
43
+
44
+ console.log('Connecting to Intiface Central...');
45
+ await client.connect(connector);
46
+
47
+ // We're connected!
48
+ console.log('Connected! Check Intiface Central for the client name.');
49
+ await waitForEnter('Press Enter to disconnect...');
50
+
51
+ // Disconnect cleanly
52
+ await client.disconnect();
53
+ console.log('Disconnected.');
54
+ } catch (e) {
55
+ if (e instanceof ButtplugClientConnectorException) {
56
+ // Connection failed - server not running, wrong address, network issues, etc.
57
+ console.log(`Can't connect to server: ${e.message}`);
58
+ console.log(
59
+ 'Make sure Intiface Central is running and the server is started.'
60
+ );
61
+ } else if (e instanceof ButtplugInitError) {
62
+ // Client/server version mismatch - need to upgrade one or the other
63
+ console.log(`Handshake failed: ${e.message}`);
64
+ console.log('Client and server versions may be incompatible.');
65
+ } else if (e instanceof ButtplugError) {
66
+ // Other Buttplug-specific errors
67
+ console.log(`Buttplug error: ${e.message}`);
68
+ } else {
69
+ throw e;
70
+ }
71
+ }
72
+
73
+ await waitForEnter('Press Enter to exit...');
74
+ }
75
+
76
+ main().catch(console.error);
@@ -0,0 +1,131 @@
1
+ // Buttplug TypeScript - Device Control Example
2
+ //
3
+ // This example demonstrates how to send commands to devices,
4
+ // query device capabilities, and use the command builder API.
5
+ //
6
+ // Prerequisites:
7
+ // 1. Install Intiface Central: https://intiface.com/central
8
+ // 2. Start the server in Intiface Central
9
+ // 3. Run: npx ts-node --esm device-control-example.ts
10
+
11
+ import {
12
+ ButtplugClient,
13
+ ButtplugNodeWebsocketClientConnector,
14
+ ButtplugClientDevice,
15
+ DeviceOutput,
16
+ OutputType,
17
+ InputType,
18
+ } from 'buttplug';
19
+ import * as readline from 'readline';
20
+
21
+ async function waitForEnter(prompt: string): Promise<void> {
22
+ const rl = readline.createInterface({
23
+ input: process.stdin,
24
+ output: process.stdout,
25
+ });
26
+ return new Promise((resolve) => {
27
+ rl.question(prompt, () => {
28
+ rl.close();
29
+ resolve();
30
+ });
31
+ });
32
+ }
33
+
34
+ function delay(ms: number): Promise<void> {
35
+ return new Promise((resolve) => setTimeout(resolve, ms));
36
+ }
37
+
38
+ async function main(): Promise<void> {
39
+ const client = new ButtplugClient('Device Control Example');
40
+
41
+ // Connect and scan for devices
42
+ const connector = new ButtplugNodeWebsocketClientConnector(
43
+ 'ws://127.0.0.1:12345'
44
+ );
45
+
46
+ console.log('Connecting...');
47
+ await client.connect(connector);
48
+ console.log('Connected! Scanning for devices...');
49
+
50
+ await client.startScanning();
51
+ await waitForEnter('Turn on a device, then press Enter...');
52
+ await client.stopScanning();
53
+
54
+ // Check if we have any devices
55
+ if (client.devices.size === 0) {
56
+ console.log('No devices found. Exiting.');
57
+ await client.disconnect();
58
+ return;
59
+ }
60
+
61
+ // Get the first device
62
+ const device: ButtplugClientDevice = client.devices.values().next().value!;
63
+ console.log(`\nUsing device: ${device.name}`);
64
+
65
+ // Show what output types this device supports
66
+ console.log('\nSupported output types:');
67
+ for (const [index, feature] of device.features) {
68
+ const def = (feature as any)._feature;
69
+ if (def.Output) {
70
+ for (const outputType of Object.keys(def.Output)) {
71
+ console.log(
72
+ ` - ${outputType} (Feature ${index}: ${def.FeatureDescriptor})`
73
+ );
74
+ }
75
+ }
76
+ }
77
+
78
+ // Check for vibration support and demonstrate commands
79
+ if (device.hasOutput(OutputType.Vibrate)) {
80
+ console.log('\nDevice supports vibration.');
81
+
82
+ // Use the command builder API
83
+ console.log('Vibrating at 50% using command builder...');
84
+ await device.runOutput(DeviceOutput.Vibrate.percent(0.5));
85
+ await delay(1000);
86
+
87
+ console.log('Vibrating at 75%...');
88
+ await device.runOutput(DeviceOutput.Vibrate.percent(0.75));
89
+ await delay(1000);
90
+
91
+ console.log('Vibrating at 25%...');
92
+ await device.runOutput(DeviceOutput.Vibrate.percent(0.25));
93
+ await delay(1000);
94
+
95
+ // Stop the device
96
+ console.log('Stopping device...');
97
+ await device.stop();
98
+ } else {
99
+ console.log('\nDevice does not support vibration.');
100
+ }
101
+
102
+ // Demonstrate other output types if available
103
+ if (device.hasOutput(OutputType.Rotate)) {
104
+ console.log('\nDevice supports rotation. Rotating at 50%...');
105
+ await device.runOutput(DeviceOutput.Rotate.percent(0.5));
106
+ await delay(1000);
107
+ await device.stop();
108
+ }
109
+
110
+ if (device.hasOutput(OutputType.Position)) {
111
+ console.log('\nDevice supports position control. Moving to 100% over 500ms...');
112
+ await device.runOutput(DeviceOutput.PositionWithDuration.percent(1.0, 500));
113
+ await delay(1000);
114
+ await device.runOutput(DeviceOutput.PositionWithDuration.percent(0.0, 500));
115
+ }
116
+
117
+ // Try reading battery level if supported
118
+ if (device.hasInput(InputType.Battery)) {
119
+ console.log('\nReading battery level...');
120
+ const battery = await device.battery();
121
+ console.log(`Battery: ${(battery * 100).toFixed(0)}%`);
122
+ }
123
+
124
+ await waitForEnter('\nPress Enter to disconnect...');
125
+
126
+ // Disconnect - this automatically stops all devices
127
+ await client.disconnect();
128
+ console.log('Disconnected.');
129
+ }
130
+
131
+ main().catch(console.error);