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..07203f9 100644 --- a/package.json +++ b/package.json @@ -2,15 +2,23 @@ "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", + "prepare": "npm run build", + "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"] +}