diff --git a/.npmrc b/.npmrc
index 8dd477af..41583e36 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1 +1 @@
-@buf:registry=https://buf.build/gen/npm/v1
+@jsr:registry=https://npm.jsr.io
diff --git a/package.json b/package.json
index 0ea7e064..6b060bcb 100644
--- a/package.json
+++ b/package.json
@@ -37,8 +37,8 @@
},
"homepage": "https://meshtastic.org",
"dependencies": {
- "@bufbuild/protobuf": "^1.10.0",
- "@meshtastic/js": "2.3.7-5",
+ "@bufbuild/protobuf": "^2.2.3",
+ "@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
"@noble/curves": "^1.8.1",
"@radix-ui/react-accordion": "^1.2.3",
"@radix-ui/react-checkbox": "^1.1.4",
@@ -63,44 +63,44 @@
"crypto-random-string": "^5.0.0",
"immer": "^10.1.1",
"js-cookie": "^3.0.5",
- "lucide-react": "^0.475.0",
- "mapbox-gl": "^3.9.4",
- "maplibre-gl": "4.1.2",
+ "lucide-react": "^0.477.0",
+ "mapbox-gl": "^3.10.0",
+ "maplibre-gl": "5.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-hook-form": "^7.54.2",
- "react-map-gl": "7.1.9",
+ "react-map-gl": "8.0.1",
"react-qrcode-logo": "^3.0.0",
- "react-scan": "^0.2.4",
+ "react-scan": "^0.2.8",
"rfc4648": "^1.5.4",
"vite-plugin-node-polyfills": "^0.23.0",
"zustand": "5.0.3"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
- "@tailwindcss/postcss": "^4.0.7",
+ "@tailwindcss/postcss": "^4.0.9",
"@testing-library/react": "^16.2.0",
- "@types/chrome": "^0.0.304",
+ "@types/chrome": "^0.0.307",
"@types/js-cookie": "^3.0.6",
- "@types/node": "^22.13.4",
+ "@types/node": "^22.13.7",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
- "@types/serviceworker": "^0.0.122",
- "@types/w3c-web-serial": "^1.0.7",
- "@types/web-bluetooth": "^0.0.20",
+ "@types/serviceworker": "^0.0.123",
+ "@types/w3c-web-serial": "^1.0.8",
+ "@types/web-bluetooth": "^0.0.21",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"gzipper": "^8.2.0",
- "happy-dom": "^17.1.4",
- "postcss": "^8.5.1",
+ "happy-dom": "^17.1.8",
+ "postcss": "^8.5.3",
"simple-git-hooks": "^2.11.1",
- "tailwind-merge": "^3.0.1",
- "tailwindcss": "^4.0.7",
+ "tailwind-merge": "^3.0.2",
+ "tailwindcss": "^4.0.9",
"tailwindcss-animate": "^1.0.7",
"tar": "^7.4.3",
- "typescript": "^5.7.3",
- "vite": "^6.1.1",
+ "typescript": "^5.8.2",
+ "vite": "^6.2.0",
"vite-plugin-pwa": "^0.21.1",
- "vitest": "^3.0.6"
+ "vitest": "^3.0.7"
}
}
diff --git a/src/App.tsx b/src/App.tsx
index eb5bb1bd..a7c278fb 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -12,7 +12,7 @@ import { useAppStore } from "@core/stores/appStore.ts";
import { useDeviceStore } from "@core/stores/deviceStore.ts";
import { Dashboard } from "@pages/Dashboard/index.tsx";
import type { JSX } from "react";
-import { MapProvider } from "react-map-gl";
+import { MapProvider } from "react-map-gl/maplibre";
export const App = (): JSX.Element => {
const { getDevice } = useDeviceStore();
@@ -36,19 +36,21 @@ export const App = (): JSX.Element => {
- {device ? (
-
- ) : (
- <>
-
-
- >
- )}
+ {device
+ ? (
+
+ )
+ : (
+ <>
+
+
+ >
+ )}
diff --git a/src/components/Dialog/DeviceNameDialog.tsx b/src/components/Dialog/DeviceNameDialog.tsx
index 1b27ed8d..d6146972 100644
--- a/src/components/Dialog/DeviceNameDialog.tsx
+++ b/src/components/Dialog/DeviceNameDialog.tsx
@@ -12,6 +12,7 @@ import { Input } from "@components/UI/Input.tsx";
import { Label } from "@components/UI/Label.tsx";
import { Protobuf } from "@meshtastic/js";
import { useForm } from "react-hook-form";
+import { create } from "@bufbuild/protobuf";
export interface User {
longName: string;
@@ -40,7 +41,7 @@ export const DeviceNameDialog = ({
const onSubmit = handleSubmit((data) => {
connection?.setOwner(
- new Protobuf.Mesh.User({
+ create(Protobuf.Mesh.UserSchema, {
...myNode?.user,
...data,
}),
diff --git a/src/components/Dialog/ImportDialog.tsx b/src/components/Dialog/ImportDialog.tsx
index 5ea39e1c..5d9e22e1 100644
--- a/src/components/Dialog/ImportDialog.tsx
+++ b/src/components/Dialog/ImportDialog.tsx
@@ -1,3 +1,4 @@
+import { create, fromBinary } from "@bufbuild/protobuf";
import { Button } from "@components/UI/Button.tsx";
import { Checkbox } from "@components/UI/Checkbox.tsx";
import {
@@ -55,7 +56,10 @@ export const ImportDialog = ({
.replace(/-/g, "+")
.replace(/_/g, "/");
setChannelSet(
- Protobuf.AppOnly.ChannelSet.fromBinary(toByteArray(paddedString)),
+ fromBinary(
+ Protobuf.AppOnly.ChannelSetSchema,
+ toByteArray(paddedString),
+ ),
);
setValidUrl(true);
} catch (error) {
@@ -67,12 +71,11 @@ export const ImportDialog = ({
const apply = () => {
channelSet?.settings.map((ch: unknown, index: number) => {
connection?.setChannel(
- new Protobuf.Channel.Channel({
+ create(Protobuf.Channel.ChannelSchema, {
index,
- role:
- index === 0
- ? Protobuf.Channel.Channel_Role.PRIMARY
- : Protobuf.Channel.Channel_Role.SECONDARY,
+ role: index === 0
+ ? Protobuf.Channel.Channel_Role.PRIMARY
+ : Protobuf.Channel.Channel_Role.SECONDARY,
settings: ch,
}),
);
@@ -80,7 +83,7 @@ export const ImportDialog = ({
if (channelSet?.loraConfig) {
connection?.setConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "lora",
value: channelSet.loraConfig,
@@ -119,21 +122,25 @@ export const ImportDialog = ({
checked={channelSet?.loraConfig?.usePreset ?? true}
/>
- {/* */}
+ */
+ }
- {/* */}
+ */
+ }
Channels:
diff --git a/src/components/Dialog/QRDialog.tsx b/src/components/Dialog/QRDialog.tsx
index 825464ec..2f4be9a5 100644
--- a/src/components/Dialog/QRDialog.tsx
+++ b/src/components/Dialog/QRDialog.tsx
@@ -1,3 +1,4 @@
+import { create, toBinary } from "@bufbuild/protobuf";
import { Checkbox } from "@components/UI/Checkbox.tsx";
import {
Dialog,
@@ -39,13 +40,16 @@ export const QRDialog = ({
.filter((ch) => selectedChannels.includes(ch.index))
.map((channel) => channel.settings)
.filter((ch): ch is Protobuf.Channel.ChannelSettings => !!ch);
- const encoded = new Protobuf.AppOnly.ChannelSet(
- new Protobuf.AppOnly.ChannelSet({
+ const encoded = create(
+ Protobuf.AppOnly.ChannelSetSchema,
+ create(Protobuf.AppOnly.ChannelSetSchema, {
loraConfig,
settings: channelsToEncode,
}),
);
- const base64 = fromByteArray(encoded.toBinary())
+ const base64 = fromByteArray(
+ toBinary(Protobuf.AppOnly.ChannelSetSchema, encoded),
+ )
.replace(/=/g, "")
.replace(/\+/g, "-")
.replace(/\//g, "_");
@@ -73,8 +77,8 @@ export const QRDialog = ({
{channel.settings?.name.length
? channel.settings.name
: channel.role === Protobuf.Channel.Channel_Role.PRIMARY
- ? "Primary"
- : `Channel: ${channel.index}`}
+ ? "Primary"
+ : `Channel: ${channel.index}`}
{
if (selectedChannels.includes(channel.index)) {
setSelectedChannels(
- selectedChannels.filter((c) => c !== channel.index),
+ selectedChannels.filter((c) =>
+ c !== channel.index
+ ),
);
} else {
setSelectedChannels([
diff --git a/src/components/PageComponents/Channel.tsx b/src/components/PageComponents/Channel.tsx
index dcd69c17..5ae88160 100644
--- a/src/components/PageComponents/Channel.tsx
+++ b/src/components/PageComponents/Channel.tsx
@@ -7,6 +7,7 @@ import { fromByteArray, toByteArray } from "base64-js";
import cryptoRandomString from "crypto-random-string";
import { useState } from "react";
import { PkiRegenerateDialog } from "../Dialog/PkiRegenerateDialog";
+import { create } from "@bufbuild/protobuf";
export interface SettingsPanelProps {
channel: Protobuf.Channel.Channel;
@@ -23,11 +24,12 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
channel?.settings?.psk.length ?? 16,
);
const [validationText, setValidationText] = useState();
- const [preSharedDialogOpen, setPreSharedDialogOpen] =
- useState(false);
+ const [preSharedDialogOpen, setPreSharedDialogOpen] = useState(
+ false,
+ );
const onSubmit = (data: ChannelValidation) => {
- const channel = new Protobuf.Channel.Channel({
+ const channel = create(Protobuf.Channel.ChannelSchema, {
...data,
settings: {
...data.settings,
@@ -106,7 +108,7 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
channel?.settings?.moduleSettings?.positionPrecision === 32,
positionPrecision:
channel?.settings?.moduleSettings?.positionPrecision ===
- undefined
+ undefined
? 10
: channel?.settings?.moduleSettings?.positionPrecision,
},
@@ -125,10 +127,9 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
description:
"Device telemetry is sent over PRIMARY. Only one PRIMARY allowed",
properties: {
- enumValue:
- channel.index === 0
- ? { PRIMARY: 1 }
- : { DISABLED: 0, SECONDARY: 2 },
+ enumValue: channel.index === 0
+ ? { PRIMARY: 1 }
+ : { DISABLED: 0, SECONDARY: 2 },
},
},
{
@@ -191,32 +192,31 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
description:
"If not sharing precise location, position shared on channel will be accurate within this distance",
properties: {
- enumValue:
- config.display?.units === 0
- ? {
- "Within 23 km": 10,
- "Within 12 km": 11,
- "Within 5.8 km": 12,
- "Within 2.9 km": 13,
- "Within 1.5 km": 14,
- "Within 700 m": 15,
- "Within 350 m": 16,
- "Within 200 m": 17,
- "Within 90 m": 18,
- "Within 50 m": 19,
- }
- : {
- "Within 15 miles": 10,
- "Within 7.3 miles": 11,
- "Within 3.6 miles": 12,
- "Within 1.8 miles": 13,
- "Within 0.9 miles": 14,
- "Within 0.5 miles": 15,
- "Within 0.2 miles": 16,
- "Within 600 feet": 17,
- "Within 300 feet": 18,
- "Within 150 feet": 19,
- },
+ enumValue: config.display?.units === 0
+ ? {
+ "Within 23 km": 10,
+ "Within 12 km": 11,
+ "Within 5.8 km": 12,
+ "Within 2.9 km": 13,
+ "Within 1.5 km": 14,
+ "Within 700 m": 15,
+ "Within 350 m": 16,
+ "Within 200 m": 17,
+ "Within 90 m": 18,
+ "Within 50 m": 19,
+ }
+ : {
+ "Within 15 miles": 10,
+ "Within 7.3 miles": 11,
+ "Within 3.6 miles": 12,
+ "Within 1.8 miles": 13,
+ "Within 0.9 miles": 14,
+ "Within 0.5 miles": 15,
+ "Within 0.2 miles": 16,
+ "Within 600 feet": 17,
+ "Within 300 feet": 18,
+ "Within 150 feet": 19,
+ },
},
},
],
diff --git a/src/components/PageComponents/Config/Bluetooth.tsx b/src/components/PageComponents/Config/Bluetooth.tsx
index 21bc7c4e..474663bd 100644
--- a/src/components/PageComponents/Config/Bluetooth.tsx
+++ b/src/components/PageComponents/Config/Bluetooth.tsx
@@ -1,5 +1,6 @@
import { useAppStore } from "@app/core/stores/appStore";
import type { BluetoothValidation } from "@app/validation/config/bluetooth.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -53,7 +54,7 @@ export const Bluetooth = () => {
}
setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "bluetooth",
value: data,
@@ -110,9 +111,8 @@ export const Bluetooth = () => {
disabledBy: [
{
fieldName: "mode",
- selector:
- Protobuf.Config.Config_BluetoothConfig_PairingMode
- .FIXED_PIN,
+ selector: Protobuf.Config.Config_BluetoothConfig_PairingMode
+ .FIXED_PIN,
invert: true,
},
{
diff --git a/src/components/PageComponents/Config/Device.tsx b/src/components/PageComponents/Config/Device.tsx
index 17ee8cb2..c06fe178 100644
--- a/src/components/PageComponents/Config/Device.tsx
+++ b/src/components/PageComponents/Config/Device.tsx
@@ -1,4 +1,5 @@
import type { DeviceValidation } from "@app/validation/config/device.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const Device = (): JSX.Element => {
const onSubmit = (data: DeviceValidation) => {
setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "device",
value: data,
diff --git a/src/components/PageComponents/Config/Display.tsx b/src/components/PageComponents/Config/Display.tsx
index 5589a8a7..64b5b368 100644
--- a/src/components/PageComponents/Config/Display.tsx
+++ b/src/components/PageComponents/Config/Display.tsx
@@ -1,4 +1,5 @@
import type { DisplayValidation } from "@app/validation/config/display.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const Display = (): JSX.Element => {
const onSubmit = (data: DisplayValidation) => {
setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "display",
value: data,
diff --git a/src/components/PageComponents/Config/LoRa.tsx b/src/components/PageComponents/Config/LoRa.tsx
index 80665f6c..8dfb81c9 100644
--- a/src/components/PageComponents/Config/LoRa.tsx
+++ b/src/components/PageComponents/Config/LoRa.tsx
@@ -1,4 +1,5 @@
import type { LoRaValidation } from "@app/validation/config/lora.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const LoRa = (): JSX.Element => {
const onSubmit = (data: LoRaValidation) => {
setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "lora",
value: data,
diff --git a/src/components/PageComponents/Config/Network.tsx b/src/components/PageComponents/Config/Network.tsx
index afda4eb5..76f1d54d 100644
--- a/src/components/PageComponents/Config/Network.tsx
+++ b/src/components/PageComponents/Config/Network.tsx
@@ -1,4 +1,5 @@
import type { NetworkValidation } from "@app/validation/config/network.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import {
@@ -12,17 +13,20 @@ export const Network = (): JSX.Element => {
const onSubmit = (data: NetworkValidation) => {
setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "network",
value: {
...data,
- ipv4Config: new Protobuf.Config.Config_NetworkConfig_IpV4Config({
- ip: convertIpAddressToInt(data.ipv4Config.ip) ?? 0,
- gateway: convertIpAddressToInt(data.ipv4Config.gateway) ?? 0,
- subnet: convertIpAddressToInt(data.ipv4Config.subnet) ?? 0,
- dns: convertIpAddressToInt(data.ipv4Config.dns) ?? 0,
- }),
+ ipv4Config: create(
+ Protobuf.Config.Config_NetworkConfig_IpV4ConfigSchema,
+ {
+ ip: convertIpAddressToInt(data.ipv4Config.ip) ?? 0,
+ gateway: convertIpAddressToInt(data.ipv4Config.gateway) ?? 0,
+ subnet: convertIpAddressToInt(data.ipv4Config.subnet) ?? 0,
+ dns: convertIpAddressToInt(data.ipv4Config.dns) ?? 0,
+ },
+ ),
},
},
}),
diff --git a/src/components/PageComponents/Config/Position.tsx b/src/components/PageComponents/Config/Position.tsx
index e81af178..4aa3abba 100644
--- a/src/components/PageComponents/Config/Position.tsx
+++ b/src/components/PageComponents/Config/Position.tsx
@@ -3,6 +3,7 @@ import {
usePositionFlags,
} from "@app/core/hooks/usePositionFlags";
import type { PositionValidation } from "@app/validation/config/position.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -16,7 +17,7 @@ export const Position = () => {
const onSubmit = (data: PositionValidation) => {
return setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "position",
value: { ...data, positionFlags: flagsValue },
diff --git a/src/components/PageComponents/Config/Power.tsx b/src/components/PageComponents/Config/Power.tsx
index 4f52be5f..e49d7ff6 100644
--- a/src/components/PageComponents/Config/Power.tsx
+++ b/src/components/PageComponents/Config/Power.tsx
@@ -1,4 +1,5 @@
import type { PowerValidation } from "@app/validation/config/power.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const Power = (): JSX.Element => {
const onSubmit = (data: PowerValidation) => {
setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "power",
value: data,
diff --git a/src/components/PageComponents/Config/Security/Security.tsx b/src/components/PageComponents/Config/Security/Security.tsx
index 85ba36fd..6047381b 100644
--- a/src/components/PageComponents/Config/Security/Security.tsx
+++ b/src/components/PageComponents/Config/Security/Security.tsx
@@ -12,6 +12,7 @@ import { fromByteArray, toByteArray } from "base64-js";
import { Eye, EyeOff } from "lucide-react";
import { useReducer } from "react";
import { securityReducer } from "./securityReducer";
+import { create } from "@bufbuild/protobuf";
export const Security = () => {
const { config, setWorkingConfig, setDialogOpen } = useDevice();
@@ -57,7 +58,9 @@ export const Security = () => {
if (input.length % 4 !== 0) {
addError(
fieldName,
- `${fieldName === "privateKey" ? "Private" : "Admin"} Key is required to be a 256 bit pre-shared key (PSK)`,
+ `${
+ fieldName === "privateKey" ? "Private" : "Admin"
+ } Key is required to be a 256 bit pre-shared key (PSK)`,
);
return;
}
@@ -71,7 +74,9 @@ export const Security = () => {
console.error(e);
addError(
fieldName,
- `Invalid ${fieldName === "privateKey" ? "Private" : "Admin"} Key format`,
+ `Invalid ${
+ fieldName === "privateKey" ? "Private" : "Admin"
+ } Key format`,
);
}
};
@@ -83,7 +88,7 @@ export const Security = () => {
console.log(toByteArray(state.adminKey));
setWorkingConfig(
- new Protobuf.Config.Config({
+ create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "security",
value: {
@@ -243,7 +248,7 @@ export const Security = () => {
? getErrorMessage("adminKey")
: "",
inputChange: adminKeyInputChangeEvent,
- selectChange: () => { },
+ selectChange: () => {},
bits: [{ text: "256 bit", value: "32", key: "bit256" }],
devicePSKBitCount: state.privateKeyBitCount,
hide: !state.adminKeyVisible,
@@ -303,8 +308,7 @@ export const Security = () => {
- dispatch({ type: "SHOW_PRIVATE_KEY_DIALOG", payload: false })
- }
+ dispatch({ type: "SHOW_PRIVATE_KEY_DIALOG", payload: false })}
onSubmit={pkiRegenerate}
/>
>
diff --git a/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx b/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx
index 978ef633..f7853710 100644
--- a/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx
+++ b/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx
@@ -1,5 +1,6 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { AmbientLightingValidation } from "@app/validation/moduleConfig/ambientLighting.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const AmbientLighting = (): JSX.Element => {
const onSubmit = (data: AmbientLightingValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "ambientLighting",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/Audio.tsx b/src/components/PageComponents/ModuleConfig/Audio.tsx
index c68bd9bf..46d2176c 100644
--- a/src/components/PageComponents/ModuleConfig/Audio.tsx
+++ b/src/components/PageComponents/ModuleConfig/Audio.tsx
@@ -1,4 +1,5 @@
import type { AudioValidation } from "@app/validation/moduleConfig/audio.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const Audio = (): JSX.Element => {
const onSubmit = (data: AudioValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "audio",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/CannedMessage.tsx b/src/components/PageComponents/ModuleConfig/CannedMessage.tsx
index 5fb1046a..672bbbb5 100644
--- a/src/components/PageComponents/ModuleConfig/CannedMessage.tsx
+++ b/src/components/PageComponents/ModuleConfig/CannedMessage.tsx
@@ -1,4 +1,5 @@
import type { CannedMessageValidation } from "@app/validation/moduleConfig/cannedMessage.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const CannedMessage = (): JSX.Element => {
const onSubmit = (data: CannedMessageValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "cannedMessage",
value: data,
@@ -62,9 +63,8 @@ export const CannedMessage = (): JSX.Element => {
label: "Clockwise event",
description: "Select input event.",
properties: {
- enumValue:
- Protobuf.ModuleConfig
- .ModuleConfig_CannedMessageConfig_InputEventChar,
+ enumValue: Protobuf.ModuleConfig
+ .ModuleConfig_CannedMessageConfig_InputEventChar,
},
},
{
@@ -73,9 +73,8 @@ export const CannedMessage = (): JSX.Element => {
label: "Counter Clockwise event",
description: "Select input event.",
properties: {
- enumValue:
- Protobuf.ModuleConfig
- .ModuleConfig_CannedMessageConfig_InputEventChar,
+ enumValue: Protobuf.ModuleConfig
+ .ModuleConfig_CannedMessageConfig_InputEventChar,
},
},
{
@@ -84,9 +83,8 @@ export const CannedMessage = (): JSX.Element => {
label: "Press event",
description: "Select input event",
properties: {
- enumValue:
- Protobuf.ModuleConfig
- .ModuleConfig_CannedMessageConfig_InputEventChar,
+ enumValue: Protobuf.ModuleConfig
+ .ModuleConfig_CannedMessageConfig_InputEventChar,
},
},
{
diff --git a/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx b/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx
index c7ec3c98..e547fab1 100644
--- a/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx
+++ b/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx
@@ -1,5 +1,6 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { DetectionSensorValidation } from "@app/validation/moduleConfig/detectionSensor.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const DetectionSensor = (): JSX.Element => {
const onSubmit = (data: DetectionSensorValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "detectionSensor",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx b/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx
index f6b52662..dfe61fad 100644
--- a/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx
+++ b/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx
@@ -1,4 +1,5 @@
import type { ExternalNotificationValidation } from "@app/validation/moduleConfig/externalNotification.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const ExternalNotification = (): JSX.Element => {
const onSubmit = (data: ExternalNotificationValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "externalNotification",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/MQTT.tsx b/src/components/PageComponents/ModuleConfig/MQTT.tsx
index bb9b1527..4b6bfe25 100644
--- a/src/components/PageComponents/ModuleConfig/MQTT.tsx
+++ b/src/components/PageComponents/ModuleConfig/MQTT.tsx
@@ -1,5 +1,6 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { MqttValidation } from "@app/validation/moduleConfig/mqtt.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
@@ -8,15 +9,16 @@ export const MQTT = (): JSX.Element => {
const onSubmit = (data: MqttValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "mqtt",
value: {
...data,
- mapReportSettings:
- new Protobuf.ModuleConfig.ModuleConfig_MapReportSettings(
- data.mapReportSettings,
- ),
+ mapReportSettings: create(
+ Protobuf.ModuleConfig
+ .ModuleConfig_MapReportSettingsSchema,
+ data.mapReportSettings,
+ ),
},
},
}),
@@ -164,32 +166,31 @@ export const MQTT = (): JSX.Element => {
description:
"Position shared will be accurate within this distance",
properties: {
- enumValue:
- config.display?.units === 0
- ? {
- "Within 23 km": 10,
- "Within 12 km": 11,
- "Within 5.8 km": 12,
- "Within 2.9 km": 13,
- "Within 1.5 km": 14,
- "Within 700 m": 15,
- "Within 350 m": 16,
- "Within 200 m": 17,
- "Within 90 m": 18,
- "Within 50 m": 19,
- }
- : {
- "Within 15 miles": 10,
- "Within 7.3 miles": 11,
- "Within 3.6 miles": 12,
- "Within 1.8 miles": 13,
- "Within 0.9 miles": 14,
- "Within 0.5 miles": 15,
- "Within 0.2 miles": 16,
- "Within 600 feet": 17,
- "Within 300 feet": 18,
- "Within 150 feet": 19,
- },
+ enumValue: config.display?.units === 0
+ ? {
+ "Within 23 km": 10,
+ "Within 12 km": 11,
+ "Within 5.8 km": 12,
+ "Within 2.9 km": 13,
+ "Within 1.5 km": 14,
+ "Within 700 m": 15,
+ "Within 350 m": 16,
+ "Within 200 m": 17,
+ "Within 90 m": 18,
+ "Within 50 m": 19,
+ }
+ : {
+ "Within 15 miles": 10,
+ "Within 7.3 miles": 11,
+ "Within 3.6 miles": 12,
+ "Within 1.8 miles": 13,
+ "Within 0.9 miles": 14,
+ "Within 0.5 miles": 15,
+ "Within 0.2 miles": 16,
+ "Within 600 feet": 17,
+ "Within 300 feet": 18,
+ "Within 150 feet": 19,
+ },
},
disabledBy: [
{
diff --git a/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx b/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx
index 9c878911..1dfa9532 100644
--- a/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx
+++ b/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx
@@ -1,5 +1,6 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { NeighborInfoValidation } from "@app/validation/moduleConfig/neighborInfo.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const NeighborInfo = (): JSX.Element => {
const onSubmit = (data: NeighborInfoValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "neighborInfo",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/Paxcounter.tsx b/src/components/PageComponents/ModuleConfig/Paxcounter.tsx
index e31a298c..d4118b8e 100644
--- a/src/components/PageComponents/ModuleConfig/Paxcounter.tsx
+++ b/src/components/PageComponents/ModuleConfig/Paxcounter.tsx
@@ -1,4 +1,5 @@
import type { PaxcounterValidation } from "@app/validation/moduleConfig/paxcounter.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const Paxcounter = (): JSX.Element => {
const onSubmit = (data: PaxcounterValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "paxcounter",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/RangeTest.tsx b/src/components/PageComponents/ModuleConfig/RangeTest.tsx
index a661805d..6c98d45a 100644
--- a/src/components/PageComponents/ModuleConfig/RangeTest.tsx
+++ b/src/components/PageComponents/ModuleConfig/RangeTest.tsx
@@ -1,4 +1,5 @@
import type { RangeTestValidation } from "@app/validation/moduleConfig/rangeTest.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const RangeTest = (): JSX.Element => {
const onSubmit = (data: RangeTestValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "rangeTest",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/Serial.tsx b/src/components/PageComponents/ModuleConfig/Serial.tsx
index 92db0d9a..e7afd3eb 100644
--- a/src/components/PageComponents/ModuleConfig/Serial.tsx
+++ b/src/components/PageComponents/ModuleConfig/Serial.tsx
@@ -1,4 +1,5 @@
import type { SerialValidation } from "@app/validation/moduleConfig/serial.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const Serial = (): JSX.Element => {
const onSubmit = (data: SerialValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "serial",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/StoreForward.tsx b/src/components/PageComponents/ModuleConfig/StoreForward.tsx
index 6fe5c585..dbd17c28 100644
--- a/src/components/PageComponents/ModuleConfig/StoreForward.tsx
+++ b/src/components/PageComponents/ModuleConfig/StoreForward.tsx
@@ -1,4 +1,5 @@
import type { StoreForwardValidation } from "@app/validation/moduleConfig/storeForward.ts";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const StoreForward = (): JSX.Element => {
const onSubmit = (data: StoreForwardValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "storeForward",
value: data,
diff --git a/src/components/PageComponents/ModuleConfig/Telemetry.tsx b/src/components/PageComponents/ModuleConfig/Telemetry.tsx
index 24074f48..c6e9f4fb 100644
--- a/src/components/PageComponents/ModuleConfig/Telemetry.tsx
+++ b/src/components/PageComponents/ModuleConfig/Telemetry.tsx
@@ -1,4 +1,5 @@
import type { TelemetryValidation } from "@app/validation/moduleConfig/telemetry.tsx";
+import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
@@ -8,7 +9,7 @@ export const Telemetry = (): JSX.Element => {
const onSubmit = (data: TelemetryValidation) => {
setWorkingModuleConfig(
- new Protobuf.ModuleConfig.ModuleConfig({
+ create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "telemetry",
value: data,
diff --git a/src/core/stores/deviceStore.ts b/src/core/stores/deviceStore.ts
index a4ad7b69..74c4453b 100644
--- a/src/core/stores/deviceStore.ts
+++ b/src/core/stores/deviceStore.ts
@@ -1,9 +1,8 @@
import { createContext, useContext } from "react";
-
import { produce } from "immer";
-import { create } from "zustand";
-
+import { create as createStore } from "zustand";
import { Protobuf, Types } from "@meshtastic/js";
+import { create } from "@bufbuild/protobuf";
export type Page = "messages" | "map" | "config" | "channels" | "nodes";
@@ -111,7 +110,7 @@ export interface DeviceState {
getDevice: (id: number) => Device | undefined;
}
-export const useDeviceStore = create((set, get) => ({
+export const useDeviceStore = createStore((set, get) => ({
devices: new Map(),
remoteDevices: new Map(),
@@ -122,11 +121,11 @@ export const useDeviceStore = create((set, get) => ({
id,
status: Types.DeviceStatusEnum.DeviceDisconnected,
channels: new Map(),
- config: new Protobuf.LocalOnly.LocalConfig(),
- moduleConfig: new Protobuf.LocalOnly.LocalModuleConfig(),
+ config: create(Protobuf.LocalOnly.LocalConfigSchema),
+ moduleConfig: create(Protobuf.LocalOnly.LocalModuleConfigSchema),
workingConfig: [],
workingModuleConfig: [],
- hardware: new Protobuf.Mesh.MyNodeInfo(),
+ hardware: create(Protobuf.Mesh.MyNodeInfoSchema),
nodes: new Map(),
metadata: new Map(),
messages: {
@@ -138,7 +137,6 @@ export const useDeviceStore = create((set, get) => ({
activePage: "messages",
activeNode: 0,
waypoints: [],
- // currentMetrics: new Protobuf.DeviceMetrics(),
dialog: {
import: false,
QR: false,
@@ -301,11 +299,11 @@ export const useDeviceStore = create((set, get) => ({
if (!device) {
return;
}
- const workingModuleConfigIndex =
- device?.workingModuleConfig.findIndex(
+ const workingModuleConfigIndex = device?.workingModuleConfig
+ .findIndex(
(wmc) =>
wmc.payloadVariant.case ===
- moduleConfig.payloadVariant.case,
+ moduleConfig.payloadVariant.case,
);
if (workingModuleConfigIndex !== -1) {
device.workingModuleConfig[workingModuleConfigIndex] =
@@ -447,8 +445,8 @@ export const useDeviceStore = create((set, get) => ({
if (!device) {
return;
}
- const currentNode =
- device.nodes.get(user.from) ?? new Protobuf.Mesh.NodeInfo();
+ const currentNode = device.nodes.get(user.from) ??
+ create(Protobuf.Mesh.NodeInfoSchema);
currentNode.user = user.data;
device.nodes.set(user.from, currentNode);
}),
@@ -461,9 +459,8 @@ export const useDeviceStore = create((set, get) => ({
if (!device) {
return;
}
- const currentNode =
- device.nodes.get(position.from) ??
- new Protobuf.Mesh.NodeInfo();
+ const currentNode = device.nodes.get(position.from) ??
+ create(Protobuf.Mesh.NodeInfoSchema);
currentNode.position = position.data;
device.nodes.set(position.from, currentNode);
}),
@@ -487,12 +484,11 @@ export const useDeviceStore = create((set, get) => ({
return;
}
const messageGroup = device.messages[message.type];
- const messageIndex =
- message.type === "direct"
- ? message.from === device.hardware.myNodeNum
- ? message.to
- : message.from
- : message.channel;
+ const messageIndex = message.type === "direct"
+ ? message.from === device.hardware.myNodeNum
+ ? message.to
+ : message.from
+ : message.channel;
const messages = messageGroup.get(messageIndex);
if (messages) {
@@ -565,12 +561,9 @@ export const useDeviceStore = create((set, get) => ({
}
const messageGroup = device.messages[type];
- const messageIndex =
- type === "direct"
- ? from === device.hardware.myNodeNum
- ? to
- : from
- : channelIndex;
+ const messageIndex = type === "direct"
+ ? from === device.hardware.myNodeNum ? to : from
+ : channelIndex;
const messages = messageGroup.get(messageIndex);
if (!messages) {
@@ -618,7 +611,7 @@ export const useDeviceStore = create((set, get) => ({
} else {
device.nodes.set(
data.from,
- new Protobuf.Mesh.NodeInfo({
+ create(Protobuf.Mesh.NodeInfoSchema, {
num: data.from,
lastHeard: data.time,
snr: data.snr,
diff --git a/src/pages/Map/index.tsx b/src/pages/Map/index.tsx
index 481b88c7..bb69825c 100644
--- a/src/pages/Map/index.tsx
+++ b/src/pages/Map/index.tsx
@@ -17,7 +17,7 @@ import {
Popup,
ScaleControl,
useMap,
-} from "react-map-gl";
+} from "react-map-gl/maplibre";
import MapGl from "react-map-gl/maplibre";
type NodePosition = {
@@ -40,8 +40,9 @@ const MapPage = (): JSX.Element => {
const darkMode = currentTheme === "dark";
- const [selectedNode, setSelectedNode] =
- useState(null);
+ const [selectedNode, setSelectedNode] = useState<
+ Protobuf.Mesh.NodeInfo | null
+ >(null);
// Filter out nodes without a valid position
const validNodes = useMemo(
@@ -185,16 +186,18 @@ const MapPage = (): JSX.Element => {
))}
{markers}
- {selectedNode ? (
- setSelectedNode(null)}
- >
-
-
- ) : null}
+ {selectedNode
+ ? (
+ setSelectedNode(null)}
+ >
+
+
+ )
+ : null}
>
diff --git a/tsconfig.json b/tsconfig.json
index 9f4e8d3f..91f1dff3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -10,8 +10,8 @@
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
- "module": "ESNext",
- "moduleResolution": "Node",
+ "module": "NodeNext",
+ "moduleResolution": "nodenext",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,