Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/.idea
/node_modules
/dist
35 changes: 35 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 <liam@liamcottle.com>",
"license": "MIT",
"dependencies": {
"@noble/curves": "^1.8.1",
"serialport": "^13.0.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"typescript": "^5.7.0"
}
}
31 changes: 19 additions & 12 deletions src/advert.js → src/advert.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import BufferReader from "./buffer_reader.js";
import BufferWriter from "./buffer_writer.js";
import type { ParsedAdvertAppData } from "./types.js";

class Advert {

Expand All @@ -13,15 +14,21 @@ 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;
this.appData = appData;
this.parsed = this.parseAppData();
}

static fromBytes(bytes) {
static fromBytes(bytes: Uint8Array): Advert {

// read bytes
const bufferReader = new BufferReader(bytes);
Expand All @@ -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";
Expand All @@ -52,7 +59,7 @@ class Advert {
return null;
}

async isVerified() {
async isVerified(): Promise<boolean> {

const { ed25519 } = await import("@noble/curves/ed25519");

Expand All @@ -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();
}
Expand Down
40 changes: 22 additions & 18 deletions src/buffer_reader.js → src/buffer_reader.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
class BufferReader {

constructor(data) {
pointer: number;
buffer: Uint8Array;

constructor(data: ArrayLike<number> | 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){

Expand All @@ -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();
Expand Down
10 changes: 5 additions & 5 deletions src/buffer_utils.js → src/buffer_utils.ts
Original file line number Diff line number Diff line change
@@ -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){
Expand Down
20 changes: 11 additions & 9 deletions src/buffer_writer.js → src/buffer_writer.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,54 @@
class BufferWriter {

buffer: number[];

constructor() {
this.buffer = [];
}

toBytes() {
toBytes(): Uint8Array {
return new Uint8Array(this.buffer);
}

writeBytes(bytes) {
writeBytes(bytes: ArrayLike<number>): 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));
Expand Down
Loading