@blueyerobotics/blueye-ts 3.9.0 → 3.11.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/README.md CHANGED
@@ -35,3 +35,33 @@ client.on("BatteryTel", data => {
35
35
 
36
36
  client.connect();
37
37
  ```
38
+
39
+ ## Connection states
40
+
41
+ `BlueyeClient` manages four sockets: `sub`, `rpc`, `pub`, and `sonar`. Global state events (`connecting`, `connected`, `disconnected`) are emitted when the derived state changes. Per-socket events use the `${socket}-${state}` format (e.g. `sonar-connected`, `rpc-connecting`):
42
+
43
+ ```ts
44
+ client.on("connected", () => {
45
+ console.log("all required sockets ready");
46
+ });
47
+
48
+ client.on("sonar-connected", () => {
49
+ console.log("sonar socket ready");
50
+ });
51
+ ```
52
+
53
+ The derived `client.state` reflects the aggregate of the core sockets (`sub`, `rpc`, `pub`). If a multibeam sonar is detected via `DroneInfoTel`, the sonar socket is also required for `connected`.
54
+
55
+ - `disconnected`: `connect()` has not been called.
56
+ - `connecting`: one or more required sockets are not yet ready.
57
+ - `connected`: all required sockets are ready — safe to call `sendRequest()`, `getTelemetry()`, and `sendControl()`.
58
+
59
+ `client.sonarState` reflects the sonar socket independently. If the client loses one or more sockets after being connected, the derived state moves back to `connecting`. `sendRequest()` and `sendControl()` reject unless the client is in the `connected` state.
60
+
61
+ ## Sonar support
62
+
63
+ `BlueyeClient` connects the sonar websocket endpoint at `ws://192.168.1.101:9988` when a supported multibeam device is detected in a `DroneInfoTel` message.
64
+
65
+ - On `connect()`, the sonar socket subscribes but only connects when a known multibeam device ID is found in the guest-port device list.
66
+ - Once detected, the sonar socket connects and the global `connected` state requires it to be ready.
67
+ - Sonar telemetry such as `MultibeamPingTel`, `MultibeamConfigTel`, and `MultibeamDiscoveryTel` is emitted through the same typed event interface as other telemetry messages.
package/dist/example.js CHANGED
@@ -4,14 +4,24 @@ const index_1 = require("./index");
4
4
  const main = async () => {
5
5
  const client = new index_1.BlueyeClient();
6
6
  client.on("connected", async () => {
7
- // request battery information
8
- const batteryRep = await client.sendRequest("GetBatteryReq");
9
- console.log("batteryRep:", batteryRep);
10
- // get latest battery telemetry
11
- const batteryTel = await client.getTelemetry("BatteryTel");
12
- console.log("batteryTel:", batteryTel);
13
- // send a control message to change the light intensity to 1
14
- await client.sendControl("LightsCtrl", { lights: { value: 1 } });
7
+ try {
8
+ // request battery information
9
+ const batteryRep = await client.sendRequest("GetBatteryReq");
10
+ console.log("batteryRep:", batteryRep);
11
+ // get latest battery telemetry
12
+ const batteryTel = await client.getTelemetry("BatteryTel");
13
+ console.log("batteryTel:", batteryTel);
14
+ }
15
+ catch (error) {
16
+ // console.error("Error:", error);
17
+ }
18
+ // send a control message to change the light intensity to 0.1
19
+ console.log("setting light intensity to 0.1 for 1 second...");
20
+ await client.sendControl("LightsCtrl", { lights: { value: 0.1 } });
21
+ setTimeout(async () => {
22
+ console.log("setting light intensity back to 0...");
23
+ await client.sendControl("LightsCtrl", { lights: { value: 0 } });
24
+ }, 1000);
15
25
  });
16
26
  // subscribe to battery telemetry updates
17
27
  client.on("BatteryTel", (data) => {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const index_1 = require("./index");
4
+ const main = async () => {
5
+ const client = new index_1.BlueyeClient();
6
+ client.on("connected", () => {
7
+ console.log("client connected");
8
+ });
9
+ client.on("connecting", () => {
10
+ console.log("client connecting...");
11
+ });
12
+ client.on("disconnected", () => {
13
+ console.log("client disconnected");
14
+ });
15
+ client.on("sonar-connected", () => {
16
+ console.log("sonar connected");
17
+ });
18
+ client.on("sonar-connecting", () => {
19
+ console.log("sonar connecting...");
20
+ });
21
+ client.on("MultibeamDiscoveryTel", (data) => {
22
+ console.log("received MultibeamDiscoveryTel:", data.discovery);
23
+ });
24
+ client.on("MultibeamConfigTel", (data) => {
25
+ console.log("received MultibeamConfigTel:", data.config);
26
+ });
27
+ client.on("MultibeamPingTel", (data) => {
28
+ const ping = data.ping;
29
+ if (!ping) {
30
+ return;
31
+ }
32
+ console.log("received MultibeamPingTel:", {
33
+ deviceId: ping.deviceId,
34
+ range: ping.range,
35
+ beams: ping.numberOfBeams,
36
+ ranges: ping.numberOfRanges,
37
+ });
38
+ });
39
+ client.connect();
40
+ };
41
+ main();
@@ -35,4 +35,18 @@ export declare const parseMessages: (decompressed: Uint8Array, fixTimes?: boolea
35
35
  * @param messages The messages to fix the times for.
36
36
  * @returns The messages with corrected times.
37
37
  */
38
+ /**
39
+ * Parse a single varint-prefixed BinlogRecord from raw (uncompressed) bytes.
40
+ * Used for streaming playback where individual frames are fetched via HTTP Range requests.
41
+ * @param bytes Raw bytes containing a single varint-length-prefixed BinlogRecord.
42
+ * @returns The parsed message, or null if the record is not a known protocol type.
43
+ */
44
+ export declare const parseFrame: (bytes: Uint8Array) => Message | null;
45
+ /**
46
+ * Parse multiple contiguous varint-prefixed BinlogRecords from raw (uncompressed) bytes.
47
+ * Used for streaming playback where frame batches are fetched via HTTP Range requests.
48
+ * @param bytes Raw bytes containing one or more varint-length-prefixed BinlogRecords.
49
+ * @returns An array of parsed messages.
50
+ */
51
+ export declare const parseFrames: (bytes: Uint8Array) => Message[];
38
52
  export declare const fixMessageTimes: (messages: Message[]) => Message[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fixMessageTimes = exports.parseMessages = exports.decompress = exports.parse = void 0;
3
+ exports.fixMessageTimes = exports.parseFrames = exports.parseFrame = exports.parseMessages = exports.decompress = exports.parse = void 0;
4
4
  const protocol_definitions_1 = require("@blueyerobotics/protocol-definitions");
5
5
  const wire_1 = require("@bufbuild/protobuf/wire");
6
6
  const buffer_1 = require("buffer");
@@ -115,6 +115,27 @@ exports.parseMessages = parseMessages;
115
115
  * @param messages The messages to fix the times for.
116
116
  * @returns The messages with corrected times.
117
117
  */
118
+ /**
119
+ * Parse a single varint-prefixed BinlogRecord from raw (uncompressed) bytes.
120
+ * Used for streaming playback where individual frames are fetched via HTTP Range requests.
121
+ * @param bytes Raw bytes containing a single varint-length-prefixed BinlogRecord.
122
+ * @returns The parsed message, or null if the record is not a known protocol type.
123
+ */
124
+ const parseFrame = (bytes) => {
125
+ const messages = (0, exports.parseFrames)(bytes);
126
+ return messages.length > 0 ? messages[0] : null;
127
+ };
128
+ exports.parseFrame = parseFrame;
129
+ /**
130
+ * Parse multiple contiguous varint-prefixed BinlogRecords from raw (uncompressed) bytes.
131
+ * Used for streaming playback where frame batches are fetched via HTTP Range requests.
132
+ * @param bytes Raw bytes containing one or more varint-length-prefixed BinlogRecords.
133
+ * @returns An array of parsed messages.
134
+ */
135
+ const parseFrames = (bytes) => {
136
+ return (0, exports.parseMessages)(bytes, false);
137
+ };
138
+ exports.parseFrames = parseFrames;
118
139
  const fixMessageTimes = (messages) => {
119
140
  if (messages.length === 0)
120
141
  return messages;
@@ -1,6 +1,7 @@
1
1
  import { blueye } from "@blueyerobotics/protocol-definitions";
2
2
  import { type LogLevel } from "consola";
3
3
  import { Emitter } from "strict-event-emitter";
4
+ export declare const MULTIBEAM_DEVICE_IDS: number[];
4
5
  export type Protocol = typeof blueye.protocol;
5
6
  export type ProtocolType = "Req" | "Rep" | "Tel" | "Ctrl";
6
7
  export type ProtocolKey = Extract<keyof Protocol, `${string}${ProtocolType}`>;
@@ -14,8 +15,11 @@ export type CreateArgs<T extends Req | Ctrl> = Parameters<MsgHandler<T>["create"
14
15
  export type DecodedOutput<T extends Req> = ReturnType<ReqToRep<T>["decode"]>;
15
16
  export type DecodedTelOutput<T extends Tel> = ReturnType<Protocol[T]["decode"]>;
16
17
  type State = "connecting" | "connected" | "disconnected";
18
+ export type SocketName = "sub" | "rpc" | "pub" | "sonar";
17
19
  export type Events = {
18
20
  [K in State]: [];
21
+ } & {
22
+ [K in `${SocketName}-${State}`]: [];
19
23
  } & {
20
24
  [K in Tel]: [DecodedTelOutput<K>];
21
25
  };
@@ -24,25 +28,34 @@ type Options = Partial<{
24
28
  subUrl: string;
25
29
  rpcUrl: string;
26
30
  pubUrl: string;
31
+ sonarUrl: string;
27
32
  timeout: number;
28
33
  reconnectInterval: number;
29
34
  logLevel: LogLevel;
30
35
  autoConnect: boolean;
31
36
  }>;
32
37
  export declare class BlueyeClient extends Emitter<Events> {
33
- state: State;
34
38
  timeout: number;
35
39
  reconnectInterval: number;
36
40
  private subUrl;
37
41
  private rpcUrl;
38
42
  private pubUrl;
43
+ private sonarUrl;
39
44
  private sub;
40
45
  private rpc;
41
46
  private pub;
47
+ private sonarSub;
42
48
  private queue;
43
49
  private logger;
44
- constructor({ subUrl, rpcUrl, pubUrl, timeout, reconnectInterval, logLevel, autoConnect, }?: Options);
45
- private updateState;
50
+ private shouldBeConnected;
51
+ private isSonarDetected;
52
+ private socketState;
53
+ constructor({ subUrl, rpcUrl, pubUrl, sonarUrl, timeout, reconnectInterval, logLevel, autoConnect, }?: Options);
54
+ get state(): State;
55
+ private updateSocketState;
56
+ private handleTelemetryMessage;
57
+ private bindSocketLifecycle;
58
+ private ensureConnected;
46
59
  connect(): void;
47
60
  disconnect(): void;
48
61
  sendRequest<T extends Req>(req: T, opts?: CreateArgs<T>): Promise<DecodedOutput<T> | null>;
@@ -1,102 +1,218 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BlueyeClient = exports.isInProtocol = void 0;
36
+ exports.BlueyeClient = exports.isInProtocol = exports.MULTIBEAM_DEVICE_IDS = void 0;
4
37
  const protocol_definitions_1 = require("@blueyerobotics/protocol-definitions");
5
38
  const buffer_1 = require("buffer");
6
39
  const consola_1 = require("consola");
7
- const jszmq_1 = require("jszmq");
40
+ const jszmq_1 = require("@blueyerobotics/jszmq");
8
41
  const strict_event_emitter_1 = require("strict-event-emitter");
9
42
  const async_queue_1 = require("./async-queue");
10
43
  const schema_1 = require("./schema");
44
+ const semver = __importStar(require("semver"));
11
45
  const DEFAULT_SUB_URL = "ws://192.168.1.101:9985";
12
46
  const DEFAULT_RPC_URL = "ws://192.168.1.101:9986";
13
47
  const DEFAULT_PUB_URL = "ws://192.168.1.101:9987";
48
+ const DEFAULT_SONAR_URL = "ws://192.168.1.101:9988";
49
+ exports.MULTIBEAM_DEVICE_IDS = [13, 16, 18, 20, 29, 30, 41, 42];
14
50
  const isInProtocol = (key) => {
15
51
  return key in protocol_definitions_1.blueye.protocol;
16
52
  };
17
53
  exports.isInProtocol = isInProtocol;
54
+ const hasSonarEndpoint = (version) => {
55
+ const coercedVersion = semver.coerce(version);
56
+ return coercedVersion
57
+ ? semver.satisfies(coercedVersion, ">=4.7.0") || version.endsWith("-dev")
58
+ : false;
59
+ };
18
60
  class BlueyeClient extends strict_event_emitter_1.Emitter {
19
- state = "disconnected";
20
61
  timeout;
21
62
  reconnectInterval;
22
63
  subUrl;
23
64
  rpcUrl;
24
65
  pubUrl;
66
+ sonarUrl;
25
67
  sub;
26
68
  rpc;
27
69
  pub;
70
+ sonarSub;
28
71
  queue;
29
72
  logger;
30
- constructor({ subUrl = DEFAULT_SUB_URL, rpcUrl = DEFAULT_RPC_URL, pubUrl = DEFAULT_PUB_URL, timeout = 2000, reconnectInterval = 2000, logLevel = consola_1.LogLevels.info, autoConnect = false, } = {}) {
73
+ shouldBeConnected = false;
74
+ isSonarDetected = false;
75
+ socketState = {
76
+ sub: "disconnected",
77
+ rpc: "disconnected",
78
+ pub: "disconnected",
79
+ sonar: "disconnected",
80
+ };
81
+ constructor({ subUrl = DEFAULT_SUB_URL, rpcUrl = DEFAULT_RPC_URL, pubUrl = DEFAULT_PUB_URL, sonarUrl = DEFAULT_SONAR_URL, timeout = 2000, reconnectInterval = 2000, logLevel = consola_1.LogLevels.info, autoConnect = false, } = {}) {
31
82
  super();
32
83
  this.timeout = timeout;
33
84
  this.reconnectInterval = reconnectInterval;
34
85
  this.subUrl = subUrl;
35
86
  this.rpcUrl = rpcUrl;
36
87
  this.pubUrl = pubUrl;
88
+ this.sonarUrl = sonarUrl;
37
89
  this.sub = new jszmq_1.Sub();
38
90
  this.rpc = new jszmq_1.Req();
39
91
  this.pub = new jszmq_1.Pub();
92
+ this.sonarSub = new jszmq_1.Sub();
40
93
  this.queue = new async_queue_1.AsyncQueue();
41
94
  this.logger = (0, consola_1.createConsola)({
42
95
  level: logLevel,
43
96
  formatOptions: { colors: true, compact: false },
44
97
  });
98
+ this.bindSocketLifecycle("sub", this.sub);
99
+ this.bindSocketLifecycle("rpc", this.rpc);
100
+ this.bindSocketLifecycle("pub", this.pub);
101
+ this.bindSocketLifecycle("sonar", this.sonarSub);
45
102
  this.sub.on("message", (topic, msg) => {
46
- const { key, data } = schema_1.responseSchema.parse({ key: topic, data: msg });
47
- if (!(0, exports.isInProtocol)(key) || !key.endsWith("Tel")) {
48
- this.logger.warn("[sub] unknown protocol:", key);
103
+ this.handleTelemetryMessage("sub", topic, msg);
104
+ });
105
+ this.sonarSub.on("message", (topic, msg) => {
106
+ this.handleTelemetryMessage("sonar", topic, msg);
107
+ });
108
+ this.once("DroneInfoTel", (msg) => {
109
+ const version = msg.droneInfo?.blunuxVersion;
110
+ if (!hasSonarEndpoint(version ?? "")) {
111
+ this.logger.warn(`[sonar] incompatible Blunux version detected in DroneInfoTel: ${version}; sonar telemetry may not be available`);
49
112
  return;
50
113
  }
51
- const protocol = protocol_definitions_1.blueye.protocol[key];
52
- const message = protocol.decode(data);
53
- this.logger.verbose("[sub] message:", key, message);
54
- this.emit(key, message);
114
+ const devices = [
115
+ ...(msg.droneInfo?.gp?.gp1?.deviceList?.devices ?? []),
116
+ ...(msg.droneInfo?.gp?.gp2?.deviceList?.devices ?? []),
117
+ ...(msg.droneInfo?.gp?.gp3?.deviceList?.devices ?? []),
118
+ ].map((device) => device.deviceId);
119
+ if (devices.some((deviceId) => exports.MULTIBEAM_DEVICE_IDS.includes(deviceId))) {
120
+ this.logger.info("[sonar] multibeam device detected in DroneInfoTel:", devices);
121
+ this.isSonarDetected = true;
122
+ this.sonarSub.connect(this.sonarUrl);
123
+ }
55
124
  });
56
125
  if (autoConnect) {
57
126
  this.connect();
58
127
  }
59
128
  }
60
- updateState(newState) {
61
- this.state = newState;
62
- this.logger.info(`[client] ${newState}`);
63
- this.emit(newState);
129
+ get state() {
130
+ if (!this.shouldBeConnected)
131
+ return "disconnected";
132
+ const { sub, rpc, pub } = this.socketState;
133
+ if (sub === "connected" &&
134
+ rpc === "connected" &&
135
+ pub === "connected" &&
136
+ (this.isSonarDetected ? this.socketState.sonar === "connected" : true)) {
137
+ return "connected";
138
+ }
139
+ return "connecting";
64
140
  }
65
- connect() {
66
- if (this.state === "connected") {
67
- this.logger.warn("[client] already connected");
141
+ updateSocketState(name, newState) {
142
+ if (this.socketState[name] === newState) {
143
+ return;
144
+ }
145
+ this.socketState[name] = newState;
146
+ this.logger.info(`[${name}] ${newState}`);
147
+ this.emit(`${name}-${newState}`);
148
+ // If all sockets are connected, emit "connected"
149
+ this.emit(this.state);
150
+ }
151
+ handleTelemetryMessage(socketName, topic, msg) {
152
+ const { key, data } = schema_1.responseSchema.parse({ key: topic, data: msg });
153
+ if (!(0, exports.isInProtocol)(key) || !key.endsWith("Tel")) {
154
+ this.logger.warn(`[${socketName}] unknown protocol:`, key);
68
155
  return;
69
156
  }
70
- if (this.state === "connecting") {
71
- this.logger.warn("[client] already connecting");
157
+ const protocol = protocol_definitions_1.blueye.protocol[key];
158
+ const message = protocol.decode(data);
159
+ this.logger.verbose(`[${socketName}] message:`, key, message);
160
+ this.emit(key, message);
161
+ }
162
+ bindSocketLifecycle(name, socket) {
163
+ socket.on("ready", () => {
164
+ if (!this.shouldBeConnected)
165
+ return;
166
+ this.updateSocketState(name, "connected");
167
+ });
168
+ socket.on("lost", () => {
169
+ if (!this.shouldBeConnected)
170
+ return;
171
+ this.updateSocketState(name, "connecting");
172
+ });
173
+ }
174
+ ensureConnected(operation) {
175
+ if (this.state !== "connected") {
176
+ throw new Error(`[client] cannot send ${operation} while ${this.state}; call connect() and wait for "connected"`);
177
+ }
178
+ }
179
+ connect() {
180
+ if (this.shouldBeConnected) {
181
+ this.logger.warn("[client] already connecting or connected");
72
182
  return;
73
183
  }
74
184
  this.sub.options.reconnectInterval = this.reconnectInterval;
75
185
  this.rpc.options.reconnectInterval = this.reconnectInterval;
76
186
  this.pub.options.reconnectInterval = this.reconnectInterval;
77
- this.updateState("connecting");
187
+ this.sonarSub.options.reconnectInterval = this.reconnectInterval;
188
+ this.shouldBeConnected = true;
189
+ for (const name of ["sub", "rpc", "pub", "sonar"]) {
190
+ this.updateSocketState(name, "connecting");
191
+ }
78
192
  this.sub.subscribe("");
79
193
  this.sub.connect(this.subUrl);
80
194
  this.rpc.connect(this.rpcUrl);
81
195
  this.pub.connect(this.pubUrl);
82
- this.updateState("connected");
196
+ this.sonarSub.subscribe("");
83
197
  }
84
198
  disconnect() {
85
- if (this.state === "disconnected") {
199
+ if (!this.shouldBeConnected) {
86
200
  this.logger.warn("[client] already disconnected");
87
201
  return;
88
202
  }
89
- if (this.state === "connecting") {
90
- this.logger.warn("[client] cannot disconnect while connecting");
91
- return;
92
- }
203
+ this.shouldBeConnected = false;
93
204
  this.sub.unsubscribe("");
94
205
  this.sub.disconnect(this.subUrl);
95
206
  this.rpc.disconnect(this.rpcUrl);
96
207
  this.pub.disconnect(this.pubUrl);
97
- this.updateState("disconnected");
208
+ this.sonarSub.unsubscribe("");
209
+ this.sonarSub.disconnect(this.sonarUrl);
210
+ for (const name of ["sub", "rpc", "pub", "sonar"]) {
211
+ this.updateSocketState(name, "disconnected");
212
+ }
98
213
  }
99
214
  async sendRequest(req, opts = {}) {
215
+ this.ensureConnected("request");
100
216
  if (!(0, exports.isInProtocol)(req) || !req.endsWith("Req")) {
101
217
  throw new Error(`[rpc] unknown protocol: ${req}`);
102
218
  }
@@ -132,6 +248,9 @@ class BlueyeClient extends strict_event_emitter_1.Emitter {
132
248
  const response = await this.sendRequest("GetTelemetryReq", {
133
249
  messageType: type,
134
250
  });
251
+ if (!response) {
252
+ throw new Error(`[rpc] no response for telemetry request: ${type}`);
253
+ }
135
254
  const { payload } = schema_1.telemetrySchema.parse(response);
136
255
  const { typeUrl, value } = payload;
137
256
  if (!(0, exports.isInProtocol)(typeUrl) || !typeUrl.endsWith("Tel")) {
@@ -142,6 +261,7 @@ class BlueyeClient extends strict_event_emitter_1.Emitter {
142
261
  return result;
143
262
  }
144
263
  async sendControl(ctrl, opts = {}) {
264
+ this.ensureConnected("control");
145
265
  if (!(0, exports.isInProtocol)(ctrl) || !ctrl.endsWith("Ctrl")) {
146
266
  throw new Error(`[pub] unknown protocol: ${ctrl}`);
147
267
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueyerobotics/blueye-ts",
3
- "version": "3.9.0",
3
+ "version": "3.11.0",
4
4
  "description": "A TypeScript client for interacting with Blueye underwater drones.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,22 +15,27 @@
15
15
  "author": "Blueye <contact@blueye.no> (https://blueye.no/)",
16
16
  "license": "LGPL-3.0-only",
17
17
  "dependencies": {
18
+ "@blueyerobotics/jszmq": "^0.2.0",
18
19
  "@blueyerobotics/protocol-definitions": "3.2.0-98aafe92",
19
20
  "@bufbuild/protobuf": "^2.11.0",
20
21
  "buffer": "^6.0.3",
21
22
  "consola": "^3.4.2",
22
23
  "fflate": "^0.8.2",
23
- "jszmq": "^0.1.2",
24
+ "semver": "^7.7.4",
24
25
  "strict-event-emitter": "^0.5.1",
25
26
  "zod": "^4.3.6"
26
27
  },
27
28
  "devDependencies": {
28
29
  "@biomejs/biome": "2.3.14",
29
30
  "@types/node": "^25.4.0",
31
+ "@types/semver": "^7.7.1",
30
32
  "typescript": "^5.9.3"
31
33
  },
32
34
  "scripts": {
33
- "start": "node dist/example.js",
34
- "build": "tsc"
35
+ "start": "pnpm build && node dist/example.js",
36
+ "start:sonar": "pnpm build && node dist/sonar-example.js",
37
+ "build": "tsc",
38
+ "test": "pnpm build && node --test --test-concurrency=1 test/**/*.test.js",
39
+ "test:one": "node --test --test-concurrency=1"
35
40
  }
36
41
  }