From bed46e52b558ea39d2fc354ce81a62936af6da82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Baham=C3=B3ndez-Honores?= Date: Fri, 20 Feb 2026 20:07:43 -0300 Subject: [PATCH 1/2] Migrate from JavaScript to TypeScript (#2) * Migrate from JavaScript to TypeScript Convert all 16 source files from .js to .ts with full type annotations. Add types.ts with interfaces for all data structures. Export BufferReader and BufferWriter from index. Use 'as const' for literal types on constants. * Switch from pnpm to npm * Remove unused EpochSeconds type --- .gitignore | 1 + package-lock.json | 35 ++ package.json | 11 +- src/{advert.js => advert.ts} | 31 +- src/{buffer_reader.js => buffer_reader.ts} | 40 +- src/{buffer_utils.js => buffer_utils.ts} | 10 +- src/{buffer_writer.js => buffer_writer.ts} | 20 +- src/{cayenne_lpp.js => cayenne_lpp.ts} | 5 +- .../{connection.js => connection.ts} | 381 +++++++++--------- ...nection.js => nodejs_serial_connection.ts} | 15 +- ...ial_connection.js => serial_connection.ts} | 14 +- .../{tcp_connection.js => tcp_connection.ts} | 27 +- ...le_connection.js => web_ble_connection.ts} | 29 +- ...connection.js => web_serial_connection.ts} | 20 +- src/{constants.js => constants.ts} | 42 +- src/{events.js => events.ts} | 18 +- src/{index.js => index.ts} | 6 + src/{packet.js => packet.ts} | 41 +- src/{random_utils.js => random_utils.ts} | 2 +- src/types.ts | 263 ++++++++++++ tsconfig.json | 19 + 21 files changed, 714 insertions(+), 316 deletions(-) rename src/{advert.js => advert.ts} (79%) rename src/{buffer_reader.js => buffer_reader.ts} (78%) rename src/{buffer_utils.js => buffer_utils.ts} (67%) rename src/{buffer_writer.js => buffer_writer.ts} (78%) rename src/{cayenne_lpp.js => cayenne_lpp.ts} (98%) rename src/connection/{connection.js => connection.ts} (85%) rename src/connection/{nodejs_serial_connection.js => nodejs_serial_connection.ts} (80%) rename src/connection/{serial_connection.js => serial_connection.ts} (88%) rename src/connection/{tcp_connection.js => tcp_connection.ts} (84%) rename src/connection/{web_ble_connection.js => web_ble_connection.ts} (85%) rename src/connection/{web_serial_connection.js => web_serial_connection.ts} (86%) rename src/{constants.js => constants.ts} (82%) rename src/{events.js => events.ts} (66%) rename src/{index.js => index.ts} (83%) rename src/{packet.js => packet.ts} (88%) rename src/{random_utils.js => random_utils.ts} (75%) create mode 100644 src/types.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 6684c76..2905f45 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /.idea /node_modules +/dist diff --git a/package-lock.json b/package-lock.json index 3bef957..5d090b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,10 @@ "dependencies": { "@noble/curves": "^1.8.1", "serialport": "^13.0.0" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "typescript": "^5.7.0" } }, "node_modules/@noble/curves": { @@ -227,6 +231,16 @@ "url": "https://opencollective.com/serialport/donate" } }, + "node_modules/@types/node": { + "version": "22.19.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", + "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -292,6 +306,27 @@ "funding": { "url": "https://opencollective.com/serialport/donate" } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index b13a697..e8fc30b 100644 --- a/package.json +++ b/package.json @@ -2,15 +2,22 @@ "name": "@liamcottle/meshcore.js", "version": "1.11.0", "description": "", - "main": "src/index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "type": "module", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "tsc", + "prepublishOnly": "npm run build" }, + "files": ["dist"], "author": "Liam Cottle ", "license": "MIT", "dependencies": { "@noble/curves": "^1.8.1", "serialport": "^13.0.0" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "typescript": "^5.7.0" } } diff --git a/src/advert.js b/src/advert.ts similarity index 79% rename from src/advert.js rename to src/advert.ts index 5349436..a9c0878 100644 --- a/src/advert.js +++ b/src/advert.ts @@ -1,5 +1,6 @@ import BufferReader from "./buffer_reader.js"; import BufferWriter from "./buffer_writer.js"; +import type { ParsedAdvertAppData } from "./types.js"; class Advert { @@ -13,7 +14,13 @@ class Advert { static ADV_FEAT2_MASK = 0x40; static ADV_NAME_MASK = 0x80; - constructor(publicKey, timestamp, signature, appData) { + publicKey: Uint8Array; + timestamp: number; + signature: Uint8Array; + appData: Uint8Array; + parsed: ParsedAdvertAppData; + + constructor(publicKey: Uint8Array, timestamp: number, signature: Uint8Array, appData: Uint8Array) { this.publicKey = publicKey; this.timestamp = timestamp; this.signature = signature; @@ -21,7 +28,7 @@ class Advert { this.parsed = this.parseAppData(); } - static fromBytes(bytes) { + static fromBytes(bytes: Uint8Array): Advert { // read bytes const bufferReader = new BufferReader(bytes); @@ -34,16 +41,16 @@ class Advert { } - getFlags() { + getFlags(): number { return this.appData[0]; } - getType() { + getType(): number { const flags = this.getFlags(); return flags & 0x0F; } - getTypeString() { + getTypeString(): string | null { const type = this.getType(); if(type === Advert.ADV_TYPE_NONE) return "NONE"; if(type === Advert.ADV_TYPE_CHAT) return "CHAT"; @@ -52,7 +59,7 @@ class Advert { return null; } - async isVerified() { + async isVerified(): Promise { const { ed25519 } = await import("@noble/curves/ed25519"); @@ -67,34 +74,34 @@ class Advert { } - parseAppData() { + parseAppData(): ParsedAdvertAppData { // read app data const bufferReader = new BufferReader(this.appData); const flags = bufferReader.readByte(); // parse lat lon - var lat = null; - var lon = null; + var lat: number | null = null; + var lon: number | null = null; if(flags & Advert.ADV_LATLON_MASK){ lat = bufferReader.readInt32LE(); lon = bufferReader.readInt32LE(); } // parse feat1 - var feat1 = null; + var feat1: number | null = null; if(flags & Advert.ADV_FEAT1_MASK){ feat1 = bufferReader.readUInt16LE(); } // parse feat2 - var feat2 = null; + var feat2: number | null = null; if(flags & Advert.ADV_FEAT2_MASK){ feat2 = bufferReader.readUInt16LE(); } // parse name (remainder of app data) - var name = null; + var name: string | null = null; if(flags & Advert.ADV_NAME_MASK){ name = bufferReader.readString(); } diff --git a/src/buffer_reader.js b/src/buffer_reader.ts similarity index 78% rename from src/buffer_reader.js rename to src/buffer_reader.ts index 9142fbc..858f136 100644 --- a/src/buffer_reader.js +++ b/src/buffer_reader.ts @@ -1,34 +1,37 @@ class BufferReader { - constructor(data) { + pointer: number; + buffer: Uint8Array; + + constructor(data: ArrayLike | ArrayBuffer) { this.pointer = 0; this.buffer = new Uint8Array(data); } - getRemainingBytesCount() { + getRemainingBytesCount(): number { return this.buffer.length - this.pointer; } - readByte() { + readByte(): number { return this.readBytes(1)[0]; } - readBytes(count) { + readBytes(count: number): Uint8Array { const data = this.buffer.slice(this.pointer, this.pointer + count); this.pointer += count; return data; } - readRemainingBytes() { + readRemainingBytes(): Uint8Array { return this.readBytes(this.getRemainingBytesCount()); } - readString() { + readString(): string { return new TextDecoder().decode(this.readRemainingBytes()); } - readCString(maxLength) { - const value = []; + readCString(maxLength: number): string { + const value: number[] = []; const bytes = this.readBytes(maxLength); for(const byte of bytes){ @@ -40,63 +43,64 @@ class BufferReader { value.push(byte); } + return new TextDecoder().decode(new Uint8Array(value)); } - readInt8() { + readInt8(): number { const bytes = this.readBytes(1); const view = new DataView(bytes.buffer); return view.getInt8(0); } - readUInt8() { + readUInt8(): number { const bytes = this.readBytes(1); const view = new DataView(bytes.buffer); return view.getUint8(0); } - readUInt16LE() { + readUInt16LE(): number { const bytes = this.readBytes(2); const view = new DataView(bytes.buffer); return view.getUint16(0, true); } - readUInt16BE() { + readUInt16BE(): number { const bytes = this.readBytes(2); const view = new DataView(bytes.buffer); return view.getUint16(0, false); } - readUInt32LE() { + readUInt32LE(): number { const bytes = this.readBytes(4); const view = new DataView(bytes.buffer); return view.getUint32(0, true); } - readUInt32BE() { + readUInt32BE(): number { const bytes = this.readBytes(4); const view = new DataView(bytes.buffer); return view.getUint32(0, false); } - readInt16LE() { + readInt16LE(): number { const bytes = this.readBytes(2); const view = new DataView(bytes.buffer); return view.getInt16(0, true); } - readInt16BE() { + readInt16BE(): number { const bytes = this.readBytes(2); const view = new DataView(bytes.buffer); return view.getInt16(0, false); } - readInt32LE() { + readInt32LE(): number { const bytes = this.readBytes(4); const view = new DataView(bytes.buffer); return view.getInt32(0, true); } - readInt24BE() { + readInt24BE(): number { // read 24-bit (3 bytes) big endian integer var value = (this.readByte() << 16) | (this.readByte() << 8) | this.readByte(); diff --git a/src/buffer_utils.js b/src/buffer_utils.ts similarity index 67% rename from src/buffer_utils.js rename to src/buffer_utils.ts index d5ff14f..05d1db5 100644 --- a/src/buffer_utils.js +++ b/src/buffer_utils.ts @@ -1,22 +1,22 @@ class BufferUtils { - static bytesToHex(uint8Array) { + static bytesToHex(uint8Array: Uint8Array): string { return Array.from(uint8Array).map(byte => { return byte.toString(16).padStart(2, '0'); }).join(''); } - static hexToBytes(hex) { - return Uint8Array.from(hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))); + static hexToBytes(hex: string): Uint8Array { + return Uint8Array.from(hex.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16))); } - static base64ToBytes(base64) { + static base64ToBytes(base64: string): Uint8Array { return Uint8Array.from(atob(base64), (c) => { return c.charCodeAt(0); }); } - static areBuffersEqual(byteArray1, byteArray2) { + static areBuffersEqual(byteArray1: Uint8Array, byteArray2: Uint8Array): boolean { // ensure length is the same if(byteArray1.length !== byteArray2.length){ diff --git a/src/buffer_writer.js b/src/buffer_writer.ts similarity index 78% rename from src/buffer_writer.js rename to src/buffer_writer.ts index a12cb2d..8d56942 100644 --- a/src/buffer_writer.js +++ b/src/buffer_writer.ts @@ -1,52 +1,54 @@ class BufferWriter { + buffer: number[]; + constructor() { this.buffer = []; } - toBytes() { + toBytes(): Uint8Array { return new Uint8Array(this.buffer); } - writeBytes(bytes) { + writeBytes(bytes: ArrayLike): void { this.buffer = [ ...this.buffer, - ...bytes, + ...Array.from(bytes), ]; } - writeByte(byte) { + writeByte(byte: number): void { this.writeBytes([ byte, ]); } - writeUInt16LE(num) { + writeUInt16LE(num: number): void { const bytes = new Uint8Array(2); const view = new DataView(bytes.buffer); view.setUint16(0, num, true); this.writeBytes(bytes); } - writeUInt32LE(num) { + writeUInt32LE(num: number): void { const bytes = new Uint8Array(4); const view = new DataView(bytes.buffer); view.setUint32(0, num, true); this.writeBytes(bytes); } - writeInt32LE(num) { + writeInt32LE(num: number): void { const bytes = new Uint8Array(4); const view = new DataView(bytes.buffer); view.setInt32(0, num, true); this.writeBytes(bytes); } - writeString(string) { + writeString(string: string): void { this.writeBytes(new TextEncoder().encode(string)); } - writeCString(string, maxLength) { + writeCString(string: string, maxLength: number): void { // create buffer of max length const bytes = new Uint8Array(new ArrayBuffer(maxLength)); diff --git a/src/cayenne_lpp.js b/src/cayenne_lpp.ts similarity index 98% rename from src/cayenne_lpp.js rename to src/cayenne_lpp.ts index ab8cab3..b4dd8d3 100644 --- a/src/cayenne_lpp.js +++ b/src/cayenne_lpp.ts @@ -1,4 +1,5 @@ import BufferReader from "./buffer_reader.js"; +import type { TelemetryEntry } from "./types.js"; class CayenneLpp { @@ -30,10 +31,10 @@ class CayenneLpp { static LPP_SWITCH = 142; // 1 byte, 0/1 static LPP_POLYLINE = 240; // 1 byte size, 1 byte delta factor, 3 byte lon/lat 0.0001° * factor, n (size-8) bytes deltas - static parse(bytes) { + static parse(bytes: Uint8Array): TelemetryEntry[] { const buffer = new BufferReader(bytes); - const telemetry = []; + const telemetry: TelemetryEntry[] = []; while(buffer.getRemainingBytesCount() >= 2){ // need at least 2 more bytes to get channel and type diff --git a/src/connection/connection.js b/src/connection/connection.ts similarity index 85% rename from src/connection/connection.js rename to src/connection/connection.ts index 2dd2d4d..e0b236e 100644 --- a/src/connection/connection.js +++ b/src/connection/connection.ts @@ -5,10 +5,18 @@ import EventEmitter from "../events.js"; import BufferUtils from "../buffer_utils.js"; import Packet from "../packet.js"; import RandomUtils from "../random_utils.js"; +import type { + SelfInfo, Contact, ChannelInfo, DeviceInfo, BatteryVoltage, CurrTime, + SentResponse, ContactMessage, ChannelMessage, ExportContactResponse, + PrivateKeyResponse, SignStartResponse, SignatureResponse, ErrResponse, + ContactsStartResponse, EndOfContactsResponse, RepeaterStats, SyncedMessage, + PingResult, GetNeighboursResult, LoginSuccessPush, StatusResponsePush, + TelemetryResponsePush, BinaryResponsePush, TraceDataPush, +} from "../types.js"; class Connection extends EventEmitter { - async onConnected() { + async onConnected(): Promise { // tell device what protocol version we support try { @@ -22,19 +30,19 @@ class Connection extends EventEmitter { } - onDisconnected() { + onDisconnected(): void { this.emit("disconnected"); } - async close() { + async close(): Promise { throw new Error("This method must be implemented by the subclass."); } - async sendToRadioFrame(data) { + async sendToRadioFrame(data: Uint8Array): Promise { throw new Error("This method must be implemented by the subclass."); } - async sendCommandAppStart() { + async sendCommandAppStart(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.AppStart); data.writeByte(1); // appVer @@ -43,7 +51,7 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendTxtMsg(txtType, attempt, senderTimestamp, pubKeyPrefix, text) { + async sendCommandSendTxtMsg(txtType: number, attempt: number, senderTimestamp: number, pubKeyPrefix: Uint8Array, text: string): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendTxtMsg); data.writeByte(txtType); @@ -54,7 +62,7 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendChannelTxtMsg(txtType, channelIdx, senderTimestamp, text) { + async sendCommandSendChannelTxtMsg(txtType: number, channelIdx: number, senderTimestamp: number, text: string): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendChannelTxtMsg); data.writeByte(txtType); @@ -64,7 +72,7 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandGetContacts(since) { + async sendCommandGetContacts(since?: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.GetContacts); if(since){ @@ -73,34 +81,34 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandGetDeviceTime() { + async sendCommandGetDeviceTime(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.GetDeviceTime); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSetDeviceTime(epochSecs) { + async sendCommandSetDeviceTime(epochSecs: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SetDeviceTime); data.writeUInt32LE(epochSecs); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendSelfAdvert(type) { + async sendCommandSendSelfAdvert(type: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendSelfAdvert); data.writeByte(type); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSetAdvertName(name) { + async sendCommandSetAdvertName(name: string): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SetAdvertName); data.writeString(name); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandAddUpdateContact(publicKey, type, flags, outPathLen, outPath, advName, lastAdvert, advLat, advLon) { + async sendCommandAddUpdateContact(publicKey: Uint8Array, type: number, flags: number, outPathLen: number, outPath: Uint8Array, advName: string, lastAdvert: number, advLat: number, advLon: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.AddUpdateContact); data.writeBytes(publicKey); @@ -115,13 +123,13 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSyncNextMessage() { + async sendCommandSyncNextMessage(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SyncNextMessage); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSetRadioParams(radioFreq, radioBw, radioSf, radioCr) { + async sendCommandSetRadioParams(radioFreq: number, radioBw: number, radioSf: number, radioCr: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SetRadioParams); data.writeUInt32LE(radioFreq); @@ -131,21 +139,21 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSetTxPower(txPower) { + async sendCommandSetTxPower(txPower: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SetTxPower); data.writeByte(txPower); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandResetPath(pubKey) { + async sendCommandResetPath(pubKey: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.ResetPath); data.writeBytes(pubKey); // 32 bytes await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSetAdvertLatLon(lat, lon) { + async sendCommandSetAdvertLatLon(lat: number, lon: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SetAdvertLatLon); data.writeInt32LE(lat); @@ -153,14 +161,14 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandRemoveContact(pubKey) { + async sendCommandRemoveContact(pubKey: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.RemoveContact); data.writeBytes(pubKey); // 32 bytes await this.sendToRadioFrame(data.toBytes()); } - async sendCommandShareContact(pubKey) { + async sendCommandShareContact(pubKey: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.ShareContact); data.writeBytes(pubKey); // 32 bytes @@ -169,7 +177,7 @@ class Connection extends EventEmitter { // provide a public key to export that contact // not providing a public key will export local identity as a contact instead - async sendCommandExportContact(pubKey = null) { + async sendCommandExportContact(pubKey: Uint8Array | null = null): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.ExportContact); if(pubKey){ @@ -178,47 +186,47 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandImportContact(advertPacketBytes) { + async sendCommandImportContact(advertPacketBytes: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.ImportContact); data.writeBytes(advertPacketBytes); // raw advert packet bytes await this.sendToRadioFrame(data.toBytes()); } - async sendCommandReboot() { + async sendCommandReboot(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.Reboot); data.writeString("reboot"); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandGetBatteryVoltage() { + async sendCommandGetBatteryVoltage(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.GetBatteryVoltage); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandDeviceQuery(appTargetVer) { + async sendCommandDeviceQuery(appTargetVer: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.DeviceQuery); data.writeByte(appTargetVer); // e.g: 1 await this.sendToRadioFrame(data.toBytes()); } - async sendCommandExportPrivateKey() { + async sendCommandExportPrivateKey(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.ExportPrivateKey); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandImportPrivateKey(privateKey) { + async sendCommandImportPrivateKey(privateKey: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.ImportPrivateKey); data.writeBytes(privateKey); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendRawData(path, rawData) { + async sendCommandSendRawData(path: ArrayLike, rawData: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendRawData); data.writeByte(path.length); @@ -227,7 +235,7 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendLogin(publicKey, password) { + async sendCommandSendLogin(publicKey: Uint8Array, password: string): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendLogin); data.writeBytes(publicKey); // 32 bytes - id of repeater or room server @@ -235,14 +243,14 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendStatusReq(publicKey) { + async sendCommandSendStatusReq(publicKey: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendStatusReq); data.writeBytes(publicKey); // 32 bytes - id of repeater or room server await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendTelemetryReq(publicKey) { + async sendCommandSendTelemetryReq(publicKey: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendTelemetryReq); data.writeByte(0); // reserved @@ -252,7 +260,7 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendBinaryReq(publicKey, requestCodeAndParams) { + async sendCommandSendBinaryReq(publicKey: Uint8Array, requestCodeAndParams: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendBinaryReq); data.writeBytes(publicKey); // 32 bytes - public key of contact to send request to @@ -260,14 +268,14 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandGetChannel(channelIdx) { + async sendCommandGetChannel(channelIdx: number): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.GetChannel); data.writeByte(channelIdx); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSetChannel(channelIdx, name, secret) { + async sendCommandSetChannel(channelIdx: number, name: string, secret: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SetChannel); data.writeByte(channelIdx); @@ -276,26 +284,26 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSignStart() { + async sendCommandSignStart(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SignStart); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSignData(dataToSign) { + async sendCommandSignData(dataToSign: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SignData); data.writeBytes(dataToSign); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSignFinish() { + async sendCommandSignFinish(): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SignFinish); await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSendTracePath(tag, auth, path) { + async sendCommandSendTracePath(tag: number, auth: number, path: Uint8Array): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SendTracePath); data.writeUInt32LE(tag); @@ -305,14 +313,14 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } - async sendCommandSetOtherParams(manualAddContacts) { + async sendCommandSetOtherParams(manualAddContacts: number | boolean): Promise { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.SetOtherParams); - data.writeByte(manualAddContacts); // 0 or 1 + data.writeByte(manualAddContacts ? 1 : 0); // 0 or 1 await this.sendToRadioFrame(data.toBytes()); } - onFrameReceived(frame) { + onFrameReceived(frame: Uint8Array): void { // emit received frame this.emit("rx", frame); @@ -388,32 +396,32 @@ class Connection extends EventEmitter { } - onAdvertPush(bufferReader) { + onAdvertPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.Advert, { publicKey: bufferReader.readBytes(32), }); } - onPathUpdatedPush(bufferReader) { + onPathUpdatedPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.PathUpdated, { publicKey: bufferReader.readBytes(32), }); } - onSendConfirmedPush(bufferReader) { + onSendConfirmedPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.SendConfirmed, { ackCode: bufferReader.readUInt32LE(), roundTrip: bufferReader.readUInt32LE(), }); } - onMsgWaitingPush(bufferReader) { + onMsgWaitingPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.MsgWaiting, { }); } - onRawDataPush(bufferReader) { + onRawDataPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.RawData, { lastSnr: bufferReader.readInt8() / 4, lastRssi: bufferReader.readInt8(), @@ -422,14 +430,14 @@ class Connection extends EventEmitter { }); } - onLoginSuccessPush(bufferReader) { + onLoginSuccessPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.LoginSuccess, { reserved: bufferReader.readByte(), // reserved pubKeyPrefix: bufferReader.readBytes(6), // 6 bytes of public key this login success is from }); } - onStatusResponsePush(bufferReader) { + onStatusResponsePush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.StatusResponse, { reserved: bufferReader.readByte(), // reserved pubKeyPrefix: bufferReader.readBytes(6), // 6 bytes of public key this status response is from @@ -437,7 +445,7 @@ class Connection extends EventEmitter { }); } - onLogRxDataPush(bufferReader) { + onLogRxDataPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.LogRxData, { lastSnr: bufferReader.readInt8() / 4, lastRssi: bufferReader.readInt8(), @@ -445,7 +453,7 @@ class Connection extends EventEmitter { }); } - onTelemetryResponsePush(bufferReader) { + onTelemetryResponsePush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.TelemetryResponse, { reserved: bufferReader.readByte(), // reserved pubKeyPrefix: bufferReader.readBytes(6), // 6 bytes of public key this telemetry response is from @@ -453,7 +461,7 @@ class Connection extends EventEmitter { }); } - onBinaryResponsePush(bufferReader) { + onBinaryResponsePush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.BinaryResponse, { reserved: bufferReader.readByte(), // reserved tag: bufferReader.readUInt32LE(), // 4 bytes tag @@ -461,7 +469,7 @@ class Connection extends EventEmitter { }); } - onTraceDataPush(bufferReader) { + onTraceDataPush(bufferReader: BufferReader): void { const reserved = bufferReader.readByte(); const pathLen = bufferReader.readUInt8(); this.emit(Constants.PushCodes.TraceData, { @@ -476,7 +484,7 @@ class Connection extends EventEmitter { }); } - onNewAdvertPush(bufferReader) { + onNewAdvertPush(bufferReader: BufferReader): void { this.emit(Constants.PushCodes.NewAdvert, { publicKey: bufferReader.readBytes(32), type: bufferReader.readByte(), @@ -491,26 +499,26 @@ class Connection extends EventEmitter { }); } - onOkResponse(bufferReader) { + onOkResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.Ok, { }); } - onErrResponse(bufferReader) { + onErrResponse(bufferReader: BufferReader): void { const errCode = bufferReader.getRemainingBytesCount() > 0 ? bufferReader.readByte() : null; this.emit(Constants.ResponseCodes.Err, { errCode: errCode, }); } - onContactsStartResponse(bufferReader) { + onContactsStartResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.ContactsStart, { count: bufferReader.readUInt32LE(), }); } - onContactResponse(bufferReader) { + onContactResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.Contact, { publicKey: bufferReader.readBytes(32), type: bufferReader.readByte(), @@ -525,13 +533,13 @@ class Connection extends EventEmitter { }); } - onEndOfContactsResponse(bufferReader) { + onEndOfContactsResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.EndOfContacts, { mostRecentLastmod: bufferReader.readUInt32LE(), }); } - onSentResponse(bufferReader) { + onSentResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.Sent, { result: bufferReader.readInt8(), expectedAckCrc: bufferReader.readUInt32LE(), @@ -539,19 +547,19 @@ class Connection extends EventEmitter { }); } - onExportContactResponse(bufferReader) { + onExportContactResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.ExportContact, { advertPacketBytes: bufferReader.readRemainingBytes(), }); } - onBatteryVoltageResponse(bufferReader) { + onBatteryVoltageResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.BatteryVoltage, { batteryMilliVolts: bufferReader.readUInt16LE(), }); } - onDeviceInfoResponse(bufferReader) { + onDeviceInfoResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.DeviceInfo, { firmwareVer: bufferReader.readInt8(), reserved: bufferReader.readBytes(6), // reserved @@ -560,19 +568,19 @@ class Connection extends EventEmitter { }); } - onPrivateKeyResponse(bufferReader) { + onPrivateKeyResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.PrivateKey, { privateKey: bufferReader.readBytes(64), }); } - onDisabledResponse(bufferReader) { + onDisabledResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.Disabled, { }); } - onChannelInfoResponse(bufferReader) { + onChannelInfoResponse(bufferReader: BufferReader): void { const idx = bufferReader.readUInt8(); const name = bufferReader.readCString(32); @@ -591,20 +599,20 @@ class Connection extends EventEmitter { } - onSignStartResponse(bufferReader) { + onSignStartResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.SignStart, { reserved: bufferReader.readByte(), maxSignDataLen: bufferReader.readUInt32LE(), }); } - onSignatureResponse(bufferReader) { + onSignatureResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.Signature, { signature: bufferReader.readBytes(64), }); } - onSelfInfoResponse(bufferReader) { + onSelfInfoResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.SelfInfo, { type: bufferReader.readByte(), txPower: bufferReader.readByte(), @@ -622,19 +630,19 @@ class Connection extends EventEmitter { }); } - onCurrTimeResponse(bufferReader) { + onCurrTimeResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.CurrTime, { epochSecs: bufferReader.readUInt32LE(), }); } - onNoMoreMessagesResponse(bufferReader) { + onNoMoreMessagesResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.NoMoreMessages, { }); } - onContactMsgRecvResponse(bufferReader) { + onContactMsgRecvResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.ContactMsgRecv, { pubKeyPrefix: bufferReader.readBytes(6), pathLen: bufferReader.readByte(), @@ -644,7 +652,7 @@ class Connection extends EventEmitter { }); } - onChannelMsgRecvResponse(bufferReader) { + onChannelMsgRecvResponse(bufferReader: BufferReader): void { this.emit(Constants.ResponseCodes.ChannelMsgRecv, { channelIdx: bufferReader.readInt8(), // reserved (0 for now, ie. 'public') pathLen: bufferReader.readByte(), // 0xFF if was sent direct, otherwise hop count for flood-mode @@ -654,11 +662,11 @@ class Connection extends EventEmitter { }); } - getSelfInfo(timeoutMillis = null) { + getSelfInfo(timeoutMillis: number | null = null): Promise { return new Promise(async (resolve, reject) => { // listen for response - this.once(Constants.ResponseCodes.SelfInfo, (selfInfo) => { + this.once(Constants.ResponseCodes.SelfInfo, (selfInfo: SelfInfo) => { resolve(selfInfo); }); @@ -673,7 +681,7 @@ class Connection extends EventEmitter { }); } - async sendAdvert(type) { + async sendAdvert(type: number): Promise { return new Promise(async (resolve, reject) => { try { @@ -704,15 +712,15 @@ class Connection extends EventEmitter { }); } - async sendFloodAdvert() { + async sendFloodAdvert(): Promise { return await this.sendAdvert(Constants.SelfAdvertTypes.Flood); } - async sendZeroHopAdvert() { + async sendZeroHopAdvert(): Promise { return await this.sendAdvert(Constants.SelfAdvertTypes.ZeroHop); } - setAdvertName(name) { + setAdvertName(name: string): Promise { return new Promise(async (resolve, reject) => { try { @@ -743,7 +751,7 @@ class Connection extends EventEmitter { }); } - setAdvertLatLong(latitude, longitude) { + setAdvertLatLong(latitude: number, longitude: number): Promise { return new Promise(async (resolve, reject) => { try { @@ -774,7 +782,7 @@ class Connection extends EventEmitter { }); } - setTxPower(txPower) { + setTxPower(txPower: number): Promise { return new Promise(async (resolve, reject) => { try { @@ -805,7 +813,7 @@ class Connection extends EventEmitter { }); } - setRadioParams(radioFreq, radioBw, radioSf, radioCr) { + setRadioParams(radioFreq: number, radioBw: number, radioSf: number, radioCr: number): Promise { return new Promise(async (resolve, reject) => { try { @@ -836,12 +844,12 @@ class Connection extends EventEmitter { }); } - getContacts() { + getContacts(): Promise { return new Promise(async (resolve, reject) => { // add contacts we receive to a list - const contacts = []; - const onContactReceived = (contact) => { + const contacts: Contact[] = []; + const onContactReceived = (contact: Contact) => { contacts.push(contact); } @@ -860,7 +868,7 @@ class Connection extends EventEmitter { }); } - async findContactByName(name) { + async findContactByName(name: string): Promise { // get contacts const contacts = await this.getContacts(); @@ -872,7 +880,7 @@ class Connection extends EventEmitter { } - async findContactByPublicKeyPrefix(pubKeyPrefix) { + async findContactByPublicKeyPrefix(pubKeyPrefix: Uint8Array): Promise { // get contacts const contacts = await this.getContacts(); @@ -885,12 +893,12 @@ class Connection extends EventEmitter { } - sendTextMessage(contactPublicKey, text, type) { + sendTextMessage(contactPublicKey: Uint8Array, text: string, type?: number): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive sent response - const onSent = (response) => { + const onSent = (response: SentResponse) => { this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -921,7 +929,7 @@ class Connection extends EventEmitter { }); } - sendChannelTextMessage(channelIdx, text) { + sendChannelTextMessage(channelIdx: number, text: string): Promise { return new Promise(async (resolve, reject) => { try { @@ -956,11 +964,11 @@ class Connection extends EventEmitter { }); } - syncNextMessage() { + syncNextMessage(): Promise { return new Promise(async (resolve, reject) => { // resolve promise when we receive a contact message - const onContactMessageReceived = (message) => { + const onContactMessageReceived = (message: ContactMessage) => { this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived); this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived); this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived); @@ -970,7 +978,7 @@ class Connection extends EventEmitter { } // resolve promise when we receive a channel message - const onChannelMessageReceived = (message) => { + const onChannelMessageReceived = (message: ChannelMessage) => { this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived); this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived); this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived); @@ -998,9 +1006,9 @@ class Connection extends EventEmitter { }); } - async getWaitingMessages() { + async getWaitingMessages(): Promise { - const waitingMessages = []; + const waitingMessages: SyncedMessage[] = []; while(true){ @@ -1019,12 +1027,12 @@ class Connection extends EventEmitter { } - getDeviceTime() { + getDeviceTime(): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive sent response - const onCurrTime = (response) => { + const onCurrTime = (response: CurrTime) => { this.off(Constants.ResponseCodes.CurrTime, onCurrTime); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1050,12 +1058,12 @@ class Connection extends EventEmitter { }); } - setDeviceTime(epochSecs) { + setDeviceTime(epochSecs: number): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive ok - const onOk = (response) => { + const onOk = (response: any) => { this.off(Constants.ResponseCodes.Ok, onOk); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1081,16 +1089,16 @@ class Connection extends EventEmitter { }); } - async syncDeviceTime() { + async syncDeviceTime(): Promise { await this.setDeviceTime(Math.floor(Date.now() / 1000)); } - importContact(advertPacketBytes) { + importContact(advertPacketBytes: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive ok - const onOk = (response) => { + const onOk = (response: any) => { this.off(Constants.ResponseCodes.Ok, onOk); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1116,12 +1124,12 @@ class Connection extends EventEmitter { }); } - exportContact(pubKey = null) { + exportContact(pubKey: Uint8Array | null = null): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive export contact response - const onExportContact = (response) => { + const onExportContact = (response: ExportContactResponse) => { this.off(Constants.ResponseCodes.ExportContact, onExportContact); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1147,12 +1155,12 @@ class Connection extends EventEmitter { }); } - shareContact(pubKey) { + shareContact(pubKey: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive ok - const onOk = (response) => { + const onOk = (response: any) => { this.off(Constants.ResponseCodes.Ok, onOk); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1178,7 +1186,7 @@ class Connection extends EventEmitter { }); } - removeContact(pubKey) { + removeContact(pubKey: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { @@ -1209,7 +1217,7 @@ class Connection extends EventEmitter { }); } - addOrUpdateContact(publicKey, type, flags, outPathLen, outPath, advName, lastAdvert, advLat, advLon) { + addOrUpdateContact(publicKey: Uint8Array, type: number, flags: number, outPathLen: number, outPath: Uint8Array, advName: string, lastAdvert: number, advLat: number, advLon: number): Promise { return new Promise(async (resolve, reject) => { try { @@ -1240,7 +1248,7 @@ class Connection extends EventEmitter { }); } - setContactPath(contact, path) { + setContactPath(contact: Contact, path: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { @@ -1266,7 +1274,7 @@ class Connection extends EventEmitter { }); } - resetPath(pubKey) { + resetPath(pubKey: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { @@ -1297,7 +1305,7 @@ class Connection extends EventEmitter { }); } - reboot() { + reboot(): Promise { return new Promise(async (resolve, reject) => { try { @@ -1325,12 +1333,12 @@ class Connection extends EventEmitter { }); } - getBatteryVoltage() { + getBatteryVoltage(): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive battery voltage - const onBatteryVoltage = (response) => { + const onBatteryVoltage = (response: BatteryVoltage) => { this.off(Constants.ResponseCodes.BatteryVoltage, onBatteryVoltage); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1356,12 +1364,12 @@ class Connection extends EventEmitter { }); } - deviceQuery(appTargetVer) { + deviceQuery(appTargetVer: number): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive device info - const onDeviceInfo = (response) => { + const onDeviceInfo = (response: DeviceInfo) => { this.off(Constants.ResponseCodes.DeviceInfo, onDeviceInfo); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1387,12 +1395,12 @@ class Connection extends EventEmitter { }); } - exportPrivateKey() { + exportPrivateKey(): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive private Key - const onPrivateKey = (response) => { + const onPrivateKey = (response: PrivateKeyResponse) => { this.off(Constants.ResponseCodes.PrivateKey, onPrivateKey); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Disabled, onDisabled); @@ -1429,12 +1437,12 @@ class Connection extends EventEmitter { }); } - importPrivateKey(privateKey) { + importPrivateKey(privateKey: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive ok - const onOk = (response) => { + const onOk = (response: any) => { this.off(Constants.ResponseCodes.Ok, onOk); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Disabled, onDisabled); @@ -1471,7 +1479,7 @@ class Connection extends EventEmitter { }); } - login(contactPublicKey, password, extraTimeoutMillis = 1000) { + login(contactPublicKey: Uint8Array, password: string, extraTimeoutMillis: number = 1000): Promise { return new Promise(async (resolve, reject) => { try { @@ -1479,8 +1487,8 @@ class Connection extends EventEmitter { const publicKeyPrefix = contactPublicKey.subarray(0, 6); // listen for sent response so we can get estimated timeout - var timeoutHandler = null; - const onSent = (response) => { + var timeoutHandler: ReturnType | null = null; + const onSent = (response: SentResponse) => { // remove error listener since we received sent response this.off(Constants.ResponseCodes.Err, onErr); @@ -1497,7 +1505,7 @@ class Connection extends EventEmitter { } // resolve promise when we receive login success push code - const onLoginSuccess = (response) => { + const onLoginSuccess = (response: LoginSuccessPush) => { // make sure login success response is for this login request if(!BufferUtils.areBuffersEqual(publicKeyPrefix, response.pubKeyPrefix)){ @@ -1506,7 +1514,7 @@ class Connection extends EventEmitter { } // login successful - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.LoginSuccess, onLoginSuccess); @@ -1516,7 +1524,7 @@ class Connection extends EventEmitter { // reject promise when we receive err const onErr = () => { - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.LoginSuccess, onLoginSuccess); @@ -1537,7 +1545,7 @@ class Connection extends EventEmitter { }); } - getStatus(contactPublicKey, extraTimeoutMillis = 1000) { + getStatus(contactPublicKey: Uint8Array, extraTimeoutMillis: number = 1000): Promise { return new Promise(async (resolve, reject) => { try { @@ -1545,8 +1553,8 @@ class Connection extends EventEmitter { const publicKeyPrefix = contactPublicKey.subarray(0, 6); // listen for sent response so we can get estimated timeout - var timeoutHandler = null; - const onSent = (response) => { + var timeoutHandler: ReturnType | null = null; + const onSent = (response: SentResponse) => { // remove error listener since we received sent response this.off(Constants.ResponseCodes.Err, onErr); @@ -1563,7 +1571,7 @@ class Connection extends EventEmitter { } // resolve promise when we receive status response push code - const onStatusResponsePush = (response) => { + const onStatusResponsePush = (response: StatusResponsePush) => { // make sure login success response is for this login request if(!BufferUtils.areBuffersEqual(publicKeyPrefix, response.pubKeyPrefix)){ @@ -1572,14 +1580,14 @@ class Connection extends EventEmitter { } // status request successful - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.StatusResponse, onStatusResponsePush); // parse repeater stats from status data const bufferReader = new BufferReader(response.statusData); - const repeaterStats = { + const repeaterStats: RepeaterStats = { batt_milli_volts: bufferReader.readUInt16LE(), // uint16_t batt_milli_volts; curr_tx_queue_len: bufferReader.readUInt16LE(), // uint16_t curr_tx_queue_len; noise_floor: bufferReader.readInt16LE(), // int16_t noise_floor; @@ -1604,7 +1612,7 @@ class Connection extends EventEmitter { // reject promise when we receive err const onErr = () => { - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.StatusResponse, onStatusResponsePush); @@ -1625,7 +1633,7 @@ class Connection extends EventEmitter { }); } - getTelemetry(contactPublicKey, extraTimeoutMillis = 1000) { + getTelemetry(contactPublicKey: Uint8Array, extraTimeoutMillis: number = 1000): Promise { return new Promise(async (resolve, reject) => { try { @@ -1633,8 +1641,8 @@ class Connection extends EventEmitter { const publicKeyPrefix = contactPublicKey.subarray(0, 6); // listen for sent response so we can get estimated timeout - var timeoutHandler = null; - const onSent = (response) => { + var timeoutHandler: ReturnType | null = null; + const onSent = (response: SentResponse) => { // remove error listener since we received sent response this.off(Constants.ResponseCodes.Err, onErr); @@ -1651,7 +1659,7 @@ class Connection extends EventEmitter { } // resolve promise when we receive telemetry response push code - const onTelemetryResponsePush = (response) => { + const onTelemetryResponsePush = (response: TelemetryResponsePush) => { // make sure telemetry response is for this telemetry request if(!BufferUtils.areBuffersEqual(publicKeyPrefix, response.pubKeyPrefix)){ @@ -1660,7 +1668,7 @@ class Connection extends EventEmitter { } // telemetry request successful - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.TelemetryResponse, onTelemetryResponsePush); @@ -1671,7 +1679,7 @@ class Connection extends EventEmitter { // reject promise when we receive err const onErr = () => { - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.TelemetryResponse, onTelemetryResponsePush); @@ -1692,16 +1700,16 @@ class Connection extends EventEmitter { }); } - sendBinaryRequest(contactPublicKey, requestCodeAndParams, extraTimeoutMillis = 1000) { + sendBinaryRequest(contactPublicKey: Uint8Array, requestCodeAndParams: Uint8Array, extraTimeoutMillis: number = 1000): Promise { return new Promise(async (resolve, reject) => { try { // we need the tag for this request (provided in sent listener), so we can listen for the response - var tag = null; + var tag: number | null = null; // listen for sent response so we can get estimated timeout - var timeoutHandler = null; - const onSent = (response) => { + var timeoutHandler: ReturnType | null = null; + const onSent = (response: SentResponse) => { tag = response.expectedAckCrc; @@ -1720,7 +1728,7 @@ class Connection extends EventEmitter { } // resolve promise when we receive binary response push code - const onBinaryResponsePush = (response) => { + const onBinaryResponsePush = (response: BinaryResponsePush) => { // make sure tag matches if(tag !== response.tag){ @@ -1729,7 +1737,7 @@ class Connection extends EventEmitter { } // binary request successful - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.BinaryResponse, onBinaryResponsePush); @@ -1740,7 +1748,7 @@ class Connection extends EventEmitter { // reject promise when we receive err const onErr = () => { - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.BinaryResponse, onBinaryResponsePush); @@ -1762,7 +1770,7 @@ class Connection extends EventEmitter { } // @deprecated migrate to using tracePath instead. pingRepeaterZeroHop will be removed in a future update - pingRepeaterZeroHop(contactPublicKey, timeoutMillis) { + pingRepeaterZeroHop(contactPublicKey: Uint8Array, timeoutMillis?: number): Promise { return new Promise(async (resolve, reject) => { try { @@ -1776,7 +1784,7 @@ class Connection extends EventEmitter { var startMillis = Date.now(); // resolve promise when we receive expected response - const onLogRxDataPush = (response) => { + const onLogRxDataPush = (response: any) => { // calculate round trip time const endMillis = Date.now(); @@ -1832,11 +1840,12 @@ class Connection extends EventEmitter { } // send raw data to repeater, for it to repeat zero hop - await this.sendCommandSendRawData([ - // we set the repeater we want to ping as the path - // it should repeat our packet, and we can listen for it + // we set the repeater we want to ping as the path + // it should repeat our packet, and we can listen for it + await this.sendCommandSendRawData( contactPublicKey.subarray(0, 1), - ], rawBytes); + rawBytes, + ); } catch(e) { reject(e); @@ -1844,12 +1853,12 @@ class Connection extends EventEmitter { }); } - getChannel(channelIdx) { + getChannel(channelIdx: number): Promise { return new Promise(async (resolve, reject) => { try { // resolve promise when we receive channel info response - const onChannelInfoResponse = (response) => { + const onChannelInfoResponse = (response: ChannelInfo) => { this.off(Constants.ResponseCodes.ChannelInfo, onChannelInfoResponse); this.off(Constants.ResponseCodes.Err, onErr); resolve(response); @@ -1875,7 +1884,7 @@ class Connection extends EventEmitter { }); } - setChannel(channelIdx, name, secret) { + setChannel(channelIdx: number, name: string, secret: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { @@ -1906,16 +1915,16 @@ class Connection extends EventEmitter { }); } - async deleteChannel(channelIdx) { + async deleteChannel(channelIdx: number): Promise { return await this.setChannel(channelIdx, "", new Uint8Array(16)); } - getChannels() { + getChannels(): Promise { return new Promise(async (resolve, reject) => { // get channels until we get an error var channelIdx = 0; - const channels = []; + const channels: ChannelInfo[] = []; while(true){ // try to get next channel @@ -1935,7 +1944,7 @@ class Connection extends EventEmitter { }); } - async findChannelByName(name) { + async findChannelByName(name: string): Promise { // get channels const channels = await this.getChannels(); @@ -1947,7 +1956,7 @@ class Connection extends EventEmitter { } - async findChannelBySecret(secret) { + async findChannelBySecret(secret: Uint8Array): Promise { // get channels const channels = await this.getChannels(); @@ -1959,7 +1968,7 @@ class Connection extends EventEmitter { } - async sign(data) { + async sign(data: Uint8Array): Promise { return new Promise(async (resolve, reject) => { try { @@ -1969,7 +1978,7 @@ class Connection extends EventEmitter { const sendNextChunk = async () => { // get next chunk - var chunk; + var chunk: Uint8Array; if(bufferReader.getRemainingBytesCount() >= chunkSize){ chunk = bufferReader.readBytes(chunkSize); } else { @@ -1982,7 +1991,7 @@ class Connection extends EventEmitter { } // listen for ok to send next chunk - const onOk = async (response) => { + const onOk = async (response: any) => { // check if more chunks to send if(bufferReader.getRemainingBytesCount() > 0){ @@ -1996,14 +2005,14 @@ class Connection extends EventEmitter { } // listen for sign start - const onSignStart = async (response) => { + const onSignStart = async (response: SignStartResponse) => { this.off(Constants.ResponseCodes.SignStart, onSignStart); // check if data to sign is too long if(bufferReader.getRemainingBytesCount() > response.maxSignDataLen){ - this.off(Constants.ResponseCodes.ok, onOk); - this.off(Constants.ResponseCodes.err, onErr); + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.SignStart, onSignStart); this.off(Constants.ResponseCodes.Signature, onSignature); reject("data_too_long"); @@ -2016,18 +2025,18 @@ class Connection extends EventEmitter { } // resolve when we receive signature - const onSignature = (response) => { - this.off(Constants.ResponseCodes.ok, onOk); - this.off(Constants.ResponseCodes.err, onErr); + const onSignature = (response: SignatureResponse) => { + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.SignStart, onSignStart); this.off(Constants.ResponseCodes.Signature, onSignature); resolve(response.signature); } // reject promise when we receive err - const onErr = (response) => { - this.off(Constants.ResponseCodes.ok, onOk); - this.off(Constants.ResponseCodes.err, onErr); + const onErr = (response: any) => { + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); this.off(Constants.ResponseCodes.SignStart, onSignStart); this.off(Constants.ResponseCodes.Signature, onSignature); reject(response); @@ -2048,7 +2057,7 @@ class Connection extends EventEmitter { }); } - tracePath(path, extraTimeoutMillis = 0) { + tracePath(path: Uint8Array, extraTimeoutMillis: number = 0): Promise { return new Promise(async (resolve, reject) => { try { @@ -2056,8 +2065,8 @@ class Connection extends EventEmitter { const tag = RandomUtils.getRandomInt(0, 4294967295); // listen for sent response so we can get estimated timeout - var timeoutHandler = null; - const onSent = (response) => { + var timeoutHandler: ReturnType | null = null; + const onSent = (response: SentResponse) => { // remove error listener since we received sent response this.off(Constants.ResponseCodes.Err, onErr); @@ -2074,7 +2083,7 @@ class Connection extends EventEmitter { } // resolve promise when we receive trace data - const onTraceDataPush = (response) => { + const onTraceDataPush = (response: TraceDataPush) => { // make sure tag matches if(response.tag !== tag){ @@ -2083,7 +2092,7 @@ class Connection extends EventEmitter { } // resolve - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.TraceData, onTraceDataPush); this.off(Constants.ResponseCodes.Err, onErr); @@ -2093,7 +2102,7 @@ class Connection extends EventEmitter { // reject promise when we receive err const onErr = () => { - clearTimeout(timeoutHandler); + clearTimeout(timeoutHandler!); this.off(Constants.ResponseCodes.Sent, onSent); this.off(Constants.PushCodes.TraceData, onTraceDataPush); this.off(Constants.ResponseCodes.Err, onErr); @@ -2114,7 +2123,7 @@ class Connection extends EventEmitter { }); } - setOtherParams(manualAddContacts) { + setOtherParams(manualAddContacts: boolean): Promise { return new Promise(async (resolve, reject) => { try { @@ -2145,23 +2154,23 @@ class Connection extends EventEmitter { }); } - async setAutoAddContacts() { + async setAutoAddContacts(): Promise { return await this.setOtherParams(false); } - async setManualAddContacts() { + async setManualAddContacts(): Promise { return await this.setOtherParams(true); } // REQ_TYPE_GET_NEIGHBOURS from Repeater role // https://github.com/meshcore-dev/MeshCore/pull/833 // Repeater must be running firmware v1.9.0+ - async getNeighbours(publicKey, - count = 10, - offset = 0, - orderBy = 0, // 0=newest_to_oldest, 1=oldest_to_newest, 2=strongest_to_weakest, 3=weakest_to_strongest - pubKeyPrefixLength = 8, - ) { + async getNeighbours(publicKey: Uint8Array, + count: number = 10, + offset: number = 0, + orderBy: number = 0, // 0=newest_to_oldest, 1=oldest_to_newest, 2=strongest_to_weakest, 3=weakest_to_strongest + pubKeyPrefixLength: number = 8, + ): Promise { // get neighbours: // req_data[0] = REQ_TYPE_GET_NEIGHBOURS @@ -2189,7 +2198,7 @@ class Connection extends EventEmitter { const resultsCount = bufferReader.readUInt16LE(); // parse neighbours list - const neighbours = []; + const neighbours: { publicKeyPrefix: Uint8Array; heardSecondsAgo: number; snr: number }[] = []; for(var i = 0; i < resultsCount; i++){ // read info diff --git a/src/connection/nodejs_serial_connection.js b/src/connection/nodejs_serial_connection.ts similarity index 80% rename from src/connection/nodejs_serial_connection.js rename to src/connection/nodejs_serial_connection.ts index 4bc519d..05d345a 100644 --- a/src/connection/nodejs_serial_connection.js +++ b/src/connection/nodejs_serial_connection.ts @@ -2,15 +2,18 @@ import SerialConnection from "./serial_connection.js"; class NodeJSSerialConnection extends SerialConnection { + serialPortPath: string; + serialPort: any; + /** * @param path serial port to connect to, e.g: "/dev/ttyACM0" or "/dev/cu.usbmodem14401" */ - constructor(path) { + constructor(path: string) { super(); this.serialPortPath = path; } - async connect() { + async connect(): Promise { // note: serialport module is only available in NodeJS, you shouldn't use NodeJSSerialConnection from a web browser const { SerialPort } = await import('serialport'); @@ -30,11 +33,11 @@ class NodeJSSerialConnection extends SerialConnection { this.onDisconnected(); }); - this.serialPort.on("error", function(err) { + this.serialPort.on("error", function(err: Error) { console.log("SerialPort Error: ", err.message) }); - this.serialPort.on("data", async (data) => { + this.serialPort.on("data", async (data: Buffer) => { await this.onDataReceived(data); }); @@ -43,7 +46,7 @@ class NodeJSSerialConnection extends SerialConnection { } - async close() { + async close(): Promise { try { await this.serialPort.close(); } catch(e) { @@ -51,7 +54,7 @@ class NodeJSSerialConnection extends SerialConnection { } } - /* override */ async write(bytes) { + /* override */ async write(bytes: Uint8Array): Promise { this.serialPort.write(bytes); } diff --git a/src/connection/serial_connection.js b/src/connection/serial_connection.ts similarity index 88% rename from src/connection/serial_connection.js rename to src/connection/serial_connection.ts index b60779f..8eaf183 100644 --- a/src/connection/serial_connection.js +++ b/src/connection/serial_connection.ts @@ -5,6 +5,8 @@ import Connection from "./connection.js"; class SerialConnection extends Connection { + readBuffer: number[]; + constructor() { super(); this.readBuffer = []; @@ -13,11 +15,11 @@ class SerialConnection extends Connection { } } - async write(bytes) { + async write(bytes: Uint8Array): Promise { throw new Error("Not Implemented: write must be implemented by SerialConnection sub class."); } - async writeFrame(frameType, frameData) { + async writeFrame(frameType: number, frameData: Uint8Array): Promise { // create frame const frame = new BufferWriter(); @@ -34,18 +36,18 @@ class SerialConnection extends Connection { } - async sendToRadioFrame(data) { + async sendToRadioFrame(data: Uint8Array): Promise { // write "app to radio" frame 0x3c "<" this.emit("tx", data); await this.writeFrame(0x3c, data); } - async onDataReceived(value) { + async onDataReceived(value: ArrayLike): Promise { // append received bytes to read buffer this.readBuffer = [ ...this.readBuffer, - ...value, + ...Array.from(value), ]; // process read buffer while there is enough bytes for a frame header @@ -84,7 +86,7 @@ class SerialConnection extends Connection { this.readBuffer = this.readBuffer.slice(requiredLength); // handle received frame - this.onFrameReceived(frameData); + this.onFrameReceived(new Uint8Array(frameData)); } catch(e) { console.error("Failed to process frame", e); diff --git a/src/connection/tcp_connection.js b/src/connection/tcp_connection.ts similarity index 84% rename from src/connection/tcp_connection.js rename to src/connection/tcp_connection.ts index eab0e16..f5c9fac 100644 --- a/src/connection/tcp_connection.js +++ b/src/connection/tcp_connection.ts @@ -5,14 +5,19 @@ import Connection from "./connection.js"; class TCPConnection extends Connection { - constructor(host, port) { + host: string; + port: number; + readBuffer: number[]; + socket: any; + + constructor(host: string, port: number) { super(); this.host = host; this.port = port; this.readBuffer = []; } - async connect() { + async connect(): Promise { // note: net module is only available in NodeJS, you shouldn't use TCPConnection from a web browser const { Socket } = await import("net"); @@ -21,17 +26,17 @@ class TCPConnection extends Connection { this.socket = new Socket(); // handle received data - this.socket.on('data', (data) => { + this.socket.on('data', (data: Buffer) => { this.onSocketDataReceived(data); }); // handle errors - this.socket.on('error', (error) => { + this.socket.on('error', (error: Error) => { console.error('Connection Error', error); }); // handle socket close - this.socket.on('close', (error) => { + this.socket.on('close', (error: boolean) => { this.onDisconnected(); }); @@ -42,7 +47,7 @@ class TCPConnection extends Connection { } - onSocketDataReceived(data) { + onSocketDataReceived(data: Buffer): void { // append received bytes to read buffer this.readBuffer = [ @@ -86,7 +91,7 @@ class TCPConnection extends Connection { this.readBuffer = this.readBuffer.slice(requiredLength); // handle received frame - this.onFrameReceived(frameData); + this.onFrameReceived(new Uint8Array(frameData)); } catch(e) { console.error("Failed to process frame", e); @@ -96,7 +101,7 @@ class TCPConnection extends Connection { } - close() { + async close(): Promise { try { this.socket.destroy(); } catch(e) { @@ -104,11 +109,11 @@ class TCPConnection extends Connection { } } - async write(bytes) { + async write(bytes: Uint8Array): Promise { this.socket.write(new Uint8Array(bytes)); } - async writeFrame(frameType, frameData) { + async writeFrame(frameType: number, frameData: Uint8Array): Promise { // create frame const frame = new BufferWriter(); @@ -125,7 +130,7 @@ class TCPConnection extends Connection { } - async sendToRadioFrame(data) { + async sendToRadioFrame(data: Uint8Array): Promise { // write "app to radio" frame 0x3c "<" this.emit("tx", data); await this.writeFrame(0x3c, data); diff --git a/src/connection/web_ble_connection.js b/src/connection/web_ble_connection.ts similarity index 85% rename from src/connection/web_ble_connection.js rename to src/connection/web_ble_connection.ts index dad7c86..4254f99 100644 --- a/src/connection/web_ble_connection.js +++ b/src/connection/web_ble_connection.ts @@ -1,9 +1,20 @@ import Constants from "../constants.js"; import Connection from "./connection.js"; +declare global { + interface Navigator { + bluetooth: any; + } +} + class WebBleConnection extends Connection { - constructor(bleDevice) { + bleDevice: any; + gattServer: any; + rxCharacteristic: any; + txCharacteristic: any; + + constructor(bleDevice: any) { super(); this.bleDevice = bleDevice; this.gattServer = null; @@ -12,7 +23,7 @@ class WebBleConnection extends Connection { this.init(); } - static async open() { + static async open(): Promise { // ensure browser supports web bluetooth if(!navigator.bluetooth){ @@ -40,7 +51,7 @@ class WebBleConnection extends Connection { } - async init() { + async init(): Promise { // listen for ble disconnect this.bleDevice.addEventListener("gattserverdisconnected", () => { @@ -55,18 +66,18 @@ class WebBleConnection extends Connection { const characteristics = await service.getCharacteristics(); // find rx characteristic (we write to this one, it's where the radio reads from) - this.rxCharacteristic = characteristics.find((characteristic) => { + this.rxCharacteristic = characteristics.find((characteristic: any) => { return characteristic.uuid.toLowerCase() === Constants.Ble.CharacteristicUuidRx.toLowerCase(); }); // find tx characteristic (we read this one, it's where the radio writes to) - this.txCharacteristic = characteristics.find((characteristic) => { + this.txCharacteristic = characteristics.find((characteristic: any) => { return characteristic.uuid.toLowerCase() === Constants.Ble.CharacteristicUuidTx.toLowerCase(); }); // listen for frames from transmitted to us from the ble device await this.txCharacteristic.startNotifications(); - this.txCharacteristic.addEventListener('characteristicvaluechanged', (event) => { + this.txCharacteristic.addEventListener('characteristicvaluechanged', (event: any) => { const frame = new Uint8Array(event.target.value.buffer); this.onFrameReceived(frame); }); @@ -76,7 +87,7 @@ class WebBleConnection extends Connection { } - async close() { + async close(): Promise { try { this.gattServer?.disconnect(); this.gattServer = null; @@ -85,7 +96,7 @@ class WebBleConnection extends Connection { } } - async write(bytes) { + async write(bytes: Uint8Array): Promise { try { // fixme: NetworkError: GATT operation already in progress. // todo: implement mutex to prevent multiple writes when another write is in progress @@ -96,7 +107,7 @@ class WebBleConnection extends Connection { } } - async sendToRadioFrame(frame) { + async sendToRadioFrame(frame: Uint8Array): Promise { this.emit("tx", frame); await this.write(frame); } diff --git a/src/connection/web_serial_connection.js b/src/connection/web_serial_connection.ts similarity index 86% rename from src/connection/web_serial_connection.js rename to src/connection/web_serial_connection.ts index a9eae02..cfc3b1e 100644 --- a/src/connection/web_serial_connection.js +++ b/src/connection/web_serial_connection.ts @@ -1,8 +1,18 @@ import SerialConnection from "./serial_connection.js"; +declare global { + interface Navigator { + serial: any; + } +} + class WebSerialConnection extends SerialConnection { - constructor(serialPort) { + serialPort: any; + reader: any; + writable: any; + + constructor(serialPort: any) { super(); @@ -23,7 +33,7 @@ class WebSerialConnection extends SerialConnection { } - static async open() { + static async open(): Promise { // ensure browser supports web serial if(!navigator.serial){ @@ -45,7 +55,7 @@ class WebSerialConnection extends SerialConnection { } - async close() { + async close(): Promise { // release reader lock try { @@ -63,7 +73,7 @@ class WebSerialConnection extends SerialConnection { } - /* override */ async write(bytes) { + /* override */ async write(bytes: Uint8Array): Promise { const writer = this.writable.getWriter(); try { await writer.write(new Uint8Array(bytes)); @@ -72,7 +82,7 @@ class WebSerialConnection extends SerialConnection { } } - async readLoop() { + async readLoop(): Promise { try { while(true){ diff --git a/src/constants.js b/src/constants.ts similarity index 82% rename from src/constants.js rename to src/constants.ts index 2eb2706..6ed6a41 100644 --- a/src/constants.js +++ b/src/constants.ts @@ -1,19 +1,19 @@ class Constants { - static SupportedCompanionProtocolVersion = 1; + static readonly SupportedCompanionProtocolVersion = 1 as const; - static SerialFrameTypes = { + static readonly SerialFrameTypes = { Incoming: 0x3e, // ">" Outgoing: 0x3c, // "<" - } + } as const; - static Ble = { + static readonly Ble = { ServiceUuid: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E", CharacteristicUuidRx: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E", CharacteristicUuidTx: "6E400003-B5A3-F393-E0A9-E50E24DCCA9E", - } + } as const; - static CommandCodes = { + static readonly CommandCodes = { AppStart: 1, SendTxtMsg: 2, SendChannelTxtMsg: 3, @@ -52,9 +52,9 @@ class Constants { SendTelemetryReq: 39, SendBinaryReq: 50, - } + } as const; - static ResponseCodes = { + static readonly ResponseCodes = { Ok: 0, // todo Err: 1, // todo ContactsStart: 2, @@ -74,9 +74,9 @@ class Constants { ChannelInfo: 18, SignStart: 19, Signature: 20, - } + } as const; - static PushCodes = { + static readonly PushCodes = { Advert: 0x80, // when companion is set to auto add contacts PathUpdated: 0x81, SendConfirmed: 0x82, @@ -90,41 +90,41 @@ class Constants { NewAdvert: 0x8A, // when companion is set to manually add contacts TelemetryResponse: 0x8B, BinaryResponse: 0x8C, - } + } as const; - static ErrorCodes = { + static readonly ErrorCodes = { UnsupportedCmd: 1, NotFound: 2, TableFull: 3, BadState: 4, FileIoError: 5, IllegalArg: 6, - } + } as const; - static AdvType = { + static readonly AdvType = { None: 0, Chat: 1, Repeater: 2, Room: 3, - } + } as const; - static SelfAdvertTypes = { + static readonly SelfAdvertTypes = { ZeroHop: 0, Flood: 1, - } + } as const; - static TxtTypes = { + static readonly TxtTypes = { Plain: 0, CliData: 1, SignedPlain: 2, - } + } as const; - static BinaryRequestTypes = { + static readonly BinaryRequestTypes = { GetTelemetryData: 0x03, // #define REQ_TYPE_GET_TELEMETRY_DATA 0x03 GetAvgMinMax: 0x04, // #define REQ_TYPE_GET_AVG_MIN_MAX 0x04 GetAccessList: 0x05, // #define REQ_TYPE_GET_ACCESS_LIST 0x05 GetNeighbours: 0x06, // #define REQ_TYPE_GET_NEIGHBOURS 0x06 - } + } as const; } diff --git a/src/events.js b/src/events.ts similarity index 66% rename from src/events.js rename to src/events.ts index 606fff2..73be661 100644 --- a/src/events.js +++ b/src/events.ts @@ -1,10 +1,12 @@ class EventEmitter { + eventListenersMap: Map void)[]>; + constructor() { this.eventListenersMap = new Map(); } - on(event, callback) { + on(event: string | number, callback: (...args: any[]) => void): void { // create list of listeners for event if it doesn't exist if(!this.eventListenersMap.has(event)){ @@ -12,24 +14,24 @@ class EventEmitter { } // add listener for event - this.eventListenersMap.get(event).push(callback); + this.eventListenersMap.get(event)!.push(callback); } - off(event, callback) { + off(event: string | number, callback: (...args: any[]) => void): void { // remove callback from listeners for this event if(this.eventListenersMap.has(event)){ - const callbacks = this.eventListenersMap.get(event).filter(cb => cb !== callback); + const callbacks = this.eventListenersMap.get(event)!.filter(cb => cb !== callback); this.eventListenersMap.set(event, callbacks); } } - once(event, callback) { + once(event: string | number, callback: (...args: any[]) => void): void { // internal callback to handle the event - const internalCallback = (...data) => { + const internalCallback = (...data: any[]) => { // we received an event, so lets remove the event listener this.off(event, internalCallback); @@ -44,11 +46,11 @@ class EventEmitter { } - emit(event, ...data) { + emit(event: string | number, ...data: any[]): void { // invoke each listener for this event if(this.eventListenersMap.has(event)){ - for(const eventListener of this.eventListenersMap.get(event)){ + for(const eventListener of this.eventListenersMap.get(event)!){ setTimeout(() => eventListener(...data), 0); } } diff --git a/src/index.js b/src/index.ts similarity index 83% rename from src/index.js rename to src/index.ts index af95004..813f60c 100644 --- a/src/index.js +++ b/src/index.ts @@ -8,6 +8,8 @@ import Constants from "./constants.js"; import Advert from "./advert.js"; import Packet from "./packet.js"; import BufferUtils from "./buffer_utils.js"; +import BufferReader from "./buffer_reader.js"; +import BufferWriter from "./buffer_writer.js"; import CayenneLpp from "./cayenne_lpp.js"; export { @@ -21,5 +23,9 @@ export { Advert, Packet, BufferUtils, + BufferReader, + BufferWriter, CayenneLpp, }; + +export type * from "./types.js"; diff --git a/src/packet.js b/src/packet.ts similarity index 88% rename from src/packet.js rename to src/packet.ts index 53a2f46..f032d37 100644 --- a/src/packet.js +++ b/src/packet.ts @@ -27,8 +27,19 @@ class Packet { static PAYLOAD_TYPE_TRACE = 0x09; // trace a path, collecting SNR for each hop static PAYLOAD_TYPE_RAW_CUSTOM = 0x0F; // custom packet as raw bytes, for applications with custom encryption, payloads, etc - constructor(header, path, payload, transportCode1, transportCode2) { - + header: number; + path: Uint8Array; + payload: Uint8Array; + transportCode1: number | null; + transportCode2: number | null; + route_type: number; + route_type_string: string | null; + payload_type: number; + payload_type_string: string | null; + payload_version: number; + is_marked_do_not_retransmit: boolean; + + constructor(header: number, path: Uint8Array, payload: Uint8Array, transportCode1: number | null, transportCode2: number | null) { this.header = header; this.path = path; @@ -46,7 +57,7 @@ class Packet { } - static fromBytes(bytes) { + static fromBytes(bytes: Uint8Array): Packet { const bufferReader = new BufferReader(bytes); const header = bufferReader.readByte(); @@ -56,8 +67,8 @@ class Packet { const hasTransportCodes = routeType === Packet.ROUTE_TYPE_TRANSPORT_FLOOD || routeType === Packet.ROUTE_TYPE_TRANSPORT_DIRECT; // parse transport codes - var transportCode1 = null; - var transportCode2 = null; + var transportCode1: number | null = null; + var transportCode2: number | null = null; if(hasTransportCodes){ transportCode1 = bufferReader.readUInt16LE(); transportCode2 = bufferReader.readUInt16LE(); @@ -71,11 +82,11 @@ class Packet { } - getRouteType() { + getRouteType(): number { return this.header & Packet.PH_ROUTE_MASK; } - getRouteTypeString() { + getRouteTypeString(): string | null { switch(this.getRouteType()){ case Packet.ROUTE_TYPE_FLOOD: return "FLOOD"; case Packet.ROUTE_TYPE_DIRECT: return "DIRECT"; @@ -85,19 +96,19 @@ class Packet { } } - isRouteFlood() { + isRouteFlood(): boolean { return this.getRouteType() === Packet.ROUTE_TYPE_FLOOD; } - isRouteDirect() { + isRouteDirect(): boolean { return this.getRouteType() === Packet.ROUTE_TYPE_DIRECT; } - getPayloadType() { + getPayloadType(): number { return (this.header >> Packet.PH_TYPE_SHIFT) & Packet.PH_TYPE_MASK; } - getPayloadTypeString() { + getPayloadTypeString(): string | null { switch(this.getPayloadType()){ case Packet.PAYLOAD_TYPE_REQ: return "REQ"; case Packet.PAYLOAD_TYPE_RESPONSE: return "RESPONSE"; @@ -114,19 +125,19 @@ class Packet { } } - getPayloadVer() { + getPayloadVer(): number { return (this.header >> Packet.PH_VER_SHIFT) & Packet.PH_VER_MASK; } - markDoNotRetransmit() { + markDoNotRetransmit(): void { this.header = 0xFF; } - isMarkedDoNotRetransmit() { + isMarkedDoNotRetransmit(): boolean { return this.header === 0xFF; } - parsePayload() { + parsePayload(): any { switch(this.getPayloadType()){ case Packet.PAYLOAD_TYPE_PATH: return this.parsePayloadTypePath(); case Packet.PAYLOAD_TYPE_REQ: return this.parsePayloadTypeReq(); diff --git a/src/random_utils.js b/src/random_utils.ts similarity index 75% rename from src/random_utils.js rename to src/random_utils.ts index a66bad3..24bf727 100644 --- a/src/random_utils.js +++ b/src/random_utils.ts @@ -1,6 +1,6 @@ class RandomUtils { - static getRandomInt(min, max) { + static getRandomInt(min: number, max: number): number { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..1b20cec --- /dev/null +++ b/src/types.ts @@ -0,0 +1,263 @@ +/** Information about the connected MeshCore device/node. */ +export interface SelfInfo { + type: number; + txPower: number; + maxTxPower: number; + publicKey: Uint8Array; + advLat: number; + advLon: number; + reserved: Uint8Array; + manualAddContacts: number; + radioFreq: number; + radioBw: number; + radioSf: number; + radioCr: number; + name: string; +} + +/** A contact stored on the device. */ +export interface Contact { + publicKey: Uint8Array; + type: number; + flags: number; + outPathLen: number; + outPath: Uint8Array; + advName: string; + lastAdvert: number; + advLat: number; + advLon: number; + lastMod: number; +} + +/** A channel stored on the device. */ +export interface ChannelInfo { + channelIdx: number; + name: string; + secret: Uint8Array; +} + +/** Device info returned from a device query. */ +export interface DeviceInfo { + firmwareVer: number; + reserved: Uint8Array; + firmware_build_date: string; + manufacturerModel: string; +} + +/** Battery voltage response. */ +export interface BatteryVoltage { + batteryMilliVolts: number; +} + +/** Current time response. */ +export interface CurrTime { + epochSecs: number; +} + +/** Sent response from the device. */ +export interface SentResponse { + result: number; + expectedAckCrc: number; + estTimeout: number; +} + +/** A contact message received from the device. */ +export interface ContactMessage { + pubKeyPrefix: Uint8Array; + pathLen: number; + txtType: number; + senderTimestamp: number; + text: string; +} + +/** A channel message received from the device. */ +export interface ChannelMessage { + channelIdx: number; + pathLen: number; + txtType: number; + senderTimestamp: number; + text: string; +} + +/** Exported contact response. */ +export interface ExportContactResponse { + advertPacketBytes: Uint8Array; +} + +/** Private key response. */ +export interface PrivateKeyResponse { + privateKey: Uint8Array; +} + +/** Sign start response. */ +export interface SignStartResponse { + reserved: number; + maxSignDataLen: number; +} + +/** Signature response. */ +export interface SignatureResponse { + signature: Uint8Array; +} + +/** Error response. */ +export interface ErrResponse { + errCode: number | null; +} + +/** Contacts start response. */ +export interface ContactsStartResponse { + count: number; +} + +/** End of contacts response. */ +export interface EndOfContactsResponse { + mostRecentLastmod: number; +} + +/** Advert push data. */ +export interface AdvertPush { + publicKey: Uint8Array; +} + +/** Path updated push data. */ +export interface PathUpdatedPush { + publicKey: Uint8Array; +} + +/** Send confirmed push data. */ +export interface SendConfirmedPush { + ackCode: number; + roundTrip: number; +} + +/** Raw data push. */ +export interface RawDataPush { + lastSnr: number; + lastRssi: number; + reserved: number; + payload: Uint8Array; +} + +/** Login success push. */ +export interface LoginSuccessPush { + reserved: number; + pubKeyPrefix: Uint8Array; +} + +/** Status response push. */ +export interface StatusResponsePush { + reserved: number; + pubKeyPrefix: Uint8Array; + statusData: Uint8Array; +} + +/** Log RX data push. */ +export interface LogRxDataPush { + lastSnr: number; + lastRssi: number; + raw: Uint8Array; +} + +/** Telemetry response push. */ +export interface TelemetryResponsePush { + reserved: number; + pubKeyPrefix: Uint8Array; + lppSensorData: Uint8Array; +} + +/** Binary response push. */ +export interface BinaryResponsePush { + reserved: number; + tag: number; + responseData: Uint8Array; +} + +/** Trace data push. */ +export interface TraceDataPush { + reserved: number; + pathLen: number; + flags: number; + tag: number; + authCode: number; + pathHashes: Uint8Array; + pathSnrs: Uint8Array; + lastSnr: number; +} + +/** New advert push data. */ +export interface NewAdvertPush { + publicKey: Uint8Array; + type: number; + flags: number; + outPathLen: number; + outPath: Uint8Array; + advName: string; + lastAdvert: number; + advLat: number; + advLon: number; + lastMod: number; +} + +/** Repeater stats from status response. */ +export interface RepeaterStats { + batt_milli_volts: number; + curr_tx_queue_len: number; + noise_floor: number; + last_rssi: number; + n_packets_recv: number; + n_packets_sent: number; + total_air_time_secs: number; + total_up_time_secs: number; + n_sent_flood: number; + n_sent_direct: number; + n_recv_flood: number; + n_recv_direct: number; + err_events: number; + last_snr: number; + n_direct_dups: number; + n_flood_dups: number; +} + +/** Synced message result. */ +export interface SyncedMessage { + contactMessage?: ContactMessage; + channelMessage?: ChannelMessage; +} + +/** Ping result. */ +export interface PingResult { + rtt: number; + snr: number; + rssi: number; +} + +/** Neighbour info. */ +export interface Neighbour { + publicKeyPrefix: Uint8Array; + heardSecondsAgo: number; + snr: number; +} + +/** Get neighbours result. */ +export interface GetNeighboursResult { + totalNeighboursCount: number; + neighbours: Neighbour[]; +} + +/** Parsed advert app data. */ +export interface ParsedAdvertAppData { + type: string | null; + lat: number | null; + lon: number | null; + name: string | null; + feat1: number | null; + feat2: number | null; +} + +/** CayenneLPP telemetry entry. */ +export interface TelemetryEntry { + channel: number; + type: number; + value: number | { latitude: number; longitude: number; altitude: number }; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..da0b211 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022", "DOM"], + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": false, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} From c4146e54b858ce4d6f4d57e9e01d33deb797a9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Baham=C3=B3ndez-Honores?= Date: Sat, 21 Feb 2026 07:20:03 -0300 Subject: [PATCH 2/2] Add prepare script to build on install from GitHub --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index e8fc30b..07203f9 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "type": "module", "scripts": { "build": "tsc", + "prepare": "npm run build", "prepublishOnly": "npm run build" }, "files": ["dist"],