Browse Source

Zod WIP

pull/635/head
philon- 1 year ago
parent
commit
9ab1f160ce
  1. 2
      package.json
  2. 73
      src/validation/channel.ts
  3. 24
      src/validation/config/bluetooth.ts
  4. 64
      src/validation/config/device.ts
  5. 69
      src/validation/config/display.ts
  6. 92
      src/validation/config/lora.ts
  7. 14
      src/validation/config/network.ts
  8. 62
      src/validation/config/position.ts
  9. 49
      src/validation/config/power.ts
  10. 50
      src/validation/config/security.ts
  11. 37
      src/validation/moduleConfig/ambientLighting.ts
  12. 38
      src/validation/moduleConfig/audio.ts
  13. 65
      src/validation/moduleConfig/cannedMessage.ts
  14. 49
      src/validation/moduleConfig/detectionSensor.ts
  15. 77
      src/validation/moduleConfig/externalNotification.ts
  16. 81
      src/validation/moduleConfig/mqtt.ts
  17. 19
      src/validation/moduleConfig/neighborInfo.ts
  18. 25
      src/validation/moduleConfig/paxcounter.ts
  19. 21
      src/validation/moduleConfig/rangeTest.ts
  20. 49
      src/validation/moduleConfig/serial.ts
  21. 37
      src/validation/moduleConfig/storeForward.ts
  22. 55
      src/validation/moduleConfig/telemetry.ts
  23. 30
      src/validation/rasterSource.ts
  24. 4
      src/validation/validate.ts

2
package.json

@ -77,7 +77,7 @@
"react-qrcode-logo": "^3.0.0",
"rfc4648": "^1.5.4",
"vite-plugin-node-polyfills": "^0.23.0",
"zod": "^3.24.3",
"zod": "^3.25.0",
"zustand": "5.0.4"
},
"devDependencies": {

73
src/validation/channel.ts

@ -1,51 +1,26 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import {
IsBoolean,
IsEnum,
IsInt,
IsNumber,
IsString,
Length,
} from "class-validator";
export class ChannelValidation
implements Omit<Protobuf.Channel.Channel, keyof Message | "settings"> {
@IsNumber()
index: number;
settings: Channel_SettingsValidation;
@IsEnum(Protobuf.Channel.Channel_Role)
role: Protobuf.Channel.Channel_Role;
}
export class Channel_SettingsValidation
implements Omit<Protobuf.Channel.ChannelSettings, keyof Message | "psk"> {
@IsNumber()
channelNum: number;
@IsString()
psk: string;
@Length(0, 11)
name: string;
@IsInt()
id: number;
@IsBoolean()
uplinkEnabled: boolean;
@IsBoolean()
downlinkEnabled: boolean;
@IsBoolean()
positionEnabled: boolean;
@IsBoolean()
preciseLocation: boolean;
@IsInt()
positionPrecision: number;
}
const RoleEnum = z.enum(
Protobuf.Channel.Channel_Role,
);
export const Channel_SettingsValidationSchema = z.object({
channelNum: z.number(),
psk: z.string(),
name: z.string().min(0).max(11),
id: z.int(),
uplinkEnabled: z.boolean(),
downlinkEnabled: z.boolean(),
positionEnabled: z.boolean(),
preciseLocation: z.boolean(),
positionPrecision: z.boolean(),
});
export const ChannelValidationSchema = z.object({
index: z.number(),
settings: Channel_SettingsValidationSchema,
role: RoleEnum,
});
export type ChannelValidation = z.infer<typeof ChannelValidationSchema>;

24
src/validation/config/bluetooth.ts

@ -1,18 +1,14 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsEnum, IsInt } from "class-validator";
export class BluetoothValidation implements
Omit<
Protobuf.Config.Config_BluetoothConfig,
keyof Message | "deviceLoggingEnabled"
> {
@IsBoolean()
enabled: boolean;
const PairingModeEnum = z.enum(
Protobuf.Config.Config_BluetoothConfig_PairingMode,
);
@IsEnum(Protobuf.Config.Config_BluetoothConfig_PairingMode)
mode: Protobuf.Config.Config_BluetoothConfig_PairingMode;
export const BluetoothValidationSchema = z.object({
enabled: z.boolean(),
mode: PairingModeEnum,
fixedPin: z.int(),
});
@IsInt()
fixedPin: number;
}
export type BluetoothValidation = z.infer<typeof BluetoothValidationSchema>;

64
src/validation/config/device.ts

@ -1,42 +1,26 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsEnum, IsInt, IsString } from "class-validator";
export class DeviceValidation
implements Omit<Protobuf.Config.Config_DeviceConfig, keyof Message> {
@IsEnum(Protobuf.Config.Config_DeviceConfig_Role)
role: Protobuf.Config.Config_DeviceConfig_Role;
@IsBoolean()
serialEnabled: boolean;
@IsBoolean()
debugLogEnabled: boolean;
@IsInt()
buttonGpio: number;
@IsInt()
buzzerGpio: number;
@IsEnum(Protobuf.Config.Config_DeviceConfig_RebroadcastMode)
rebroadcastMode: Protobuf.Config.Config_DeviceConfig_RebroadcastMode;
@IsInt()
nodeInfoBroadcastSecs: number;
@IsBoolean()
doubleTapAsButtonPress: boolean;
@IsBoolean()
isManaged: boolean;
@IsBoolean()
disableTripleClick: boolean;
@IsBoolean()
ledHeartbeatDisabled: boolean;
@IsString()
tzdef: string;
}
const RoleEnum = z.enum(
Protobuf.Config.Config_DeviceConfig_Role,
);
const RebroadcastModeEnum = z.enum(
Protobuf.Config.Config_DeviceConfig_RebroadcastMode,
);
export const DeviceValidationSchema = z.object({
role: RoleEnum,
serialEnabled: z.boolean(),
debugLogEnabled: z.boolean(),
buttonGpio: z.int(),
buzzerGpio: z.int(),
rebroadcastMode: RebroadcastModeEnum,
nodeInfoBroadcastSecs: z.int(),
doubleTapAsButtonPress: z.boolean(),
isManaged: z.boolean(),
disableTripleClick: z.boolean(),
ledHeartbeatDisabled: z.boolean(),
tzdef: z.string(),
});
export type DeviceValidation = z.infer<typeof DeviceValidationSchema>;

69
src/validation/config/display.ts

@ -1,39 +1,34 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsEnum, IsInt } from "class-validator";
export class DisplayValidation
implements Omit<Protobuf.Config.Config_DisplayConfig, keyof Message> {
@IsInt()
screenOnSecs: number;
@IsEnum(Protobuf.Config.Config_DisplayConfig_GpsCoordinateFormat)
gpsFormat: Protobuf.Config.Config_DisplayConfig_GpsCoordinateFormat;
@IsInt()
autoScreenCarouselSecs: number;
@IsBoolean()
compassNorthTop: boolean;
@IsBoolean()
flipScreen: boolean;
@IsEnum(Protobuf.Config.Config_DisplayConfig_DisplayUnits)
units: Protobuf.Config.Config_DisplayConfig_DisplayUnits;
@IsEnum(Protobuf.Config.Config_DisplayConfig_OledType)
oled: Protobuf.Config.Config_DisplayConfig_OledType;
@IsEnum(Protobuf.Config.Config_DisplayConfig_DisplayMode)
displaymode: Protobuf.Config.Config_DisplayConfig_DisplayMode;
@IsBoolean()
headingBold: boolean;
@IsBoolean()
wakeOnTapOrMotion: boolean;
@IsEnum(Protobuf.Config.Config_DisplayConfig_CompassOrientation)
compassOrientation: Protobuf.Config.Config_DisplayConfig_CompassOrientation;
}
const GpsCoordinateEnum = z.enum(
Protobuf.Config.Config_DisplayConfig_GpsCoordinateFormat,
);
const DisplayUnitsEnum = z.enum(
Protobuf.Config.Config_DisplayConfig_DisplayUnits,
);
const OledTypeEnum = z.enum(
Protobuf.Config.Config_DisplayConfig_OledType,
);
const DisplayModeEnum = z.enum(
Protobuf.Config.Config_DisplayConfig_DisplayMode,
);
const CompassOrientationEnum = z.enum(
Protobuf.Config.Config_DisplayConfig_CompassOrientation,
);
export const DisplayValidationSchema = z.object({
screenOnSecs: z.int(),
gpsFormat: GpsCoordinateEnum,
autoScreenCarouselSecs: z.int(),
compassNorthTop: z.boolean(),
flipScreen: z.boolean(),
units: DisplayUnitsEnum,
oled: OledTypeEnum,
displaymode: DisplayModeEnum,
headingBold: z.boolean(),
wakeOnTapOrMotion: z.boolean(),
compassOrientation: CompassOrientationEnum,
});
export type DisplayValidation = z.infer<typeof DisplayValidationSchema>;

92
src/validation/config/lora.ts

@ -1,65 +1,31 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsArray, IsBoolean, IsEnum, IsInt, Max, Min } from "class-validator";
export class LoRaValidation
implements
Omit<Protobuf.Config.Config_LoRaConfig, keyof Message | "paFanDisabled"> {
@IsBoolean()
usePreset: boolean;
@IsEnum(Protobuf.Config.Config_LoRaConfig_ModemPreset)
modemPreset: Protobuf.Config.Config_LoRaConfig_ModemPreset;
@IsInt()
bandwidth: number;
@IsInt()
// @Min(7)
@Max(12)
spreadFactor: number;
@IsInt()
@Min(0)
@Max(10)
codingRate: number;
@IsInt()
frequencyOffset: number;
@IsEnum(Protobuf.Config.Config_LoRaConfig_RegionCode)
region: Protobuf.Config.Config_LoRaConfig_RegionCode;
@IsInt()
@Min(1)
@Max(7)
hopLimit: number;
@IsBoolean()
txEnabled: boolean;
@IsInt()
@Min(0)
txPower: number;
@IsInt()
channelNum: number;
@IsBoolean()
overrideDutyCycle: boolean;
@IsBoolean()
sx126xRxBoostedGain: boolean;
@IsInt()
overrideFrequency: number;
@IsArray()
ignoreIncoming: number[];
@IsBoolean()
ignoreMqtt: boolean;
@IsBoolean()
configOkToMqtt: boolean;
}
const ModemPresetEnum = z.enum(
Protobuf.Config.Config_LoRaConfig_ModemPreset,
);
const RegionCodeEnum = z.enum(
Protobuf.Config.Config_LoRaConfig_RegionCode,
);
export const LoRaValidationSchema = z.object({
usePreset: z.boolean(),
modemPreset: ModemPresetEnum,
bandwidth: z.int(),
spreadFactor: z.int().max(12),
codingRate: z.int().min(0).max(10),
frequencyOffset: z.int(),
region: RegionCodeEnum,
hopLimit: z.int().min(0).max(7),
txEnabled: z.boolean(),
txPower: z.int().min(0),
channelNum: z.int(),
overrideDutyCycle: z.boolean(),
sx126xRxBoostedGain: z.boolean(),
overrideFrequency: z.int(),
ignoreIncoming: z.number().array(),
ignoreMqtt: z.boolean(),
configOkToMqtt: z.boolean(),
});
export type LoRaValidation = z.infer<typeof LoRaValidationSchema>;

14
src/validation/config/network.ts

@ -1,18 +1,18 @@
import { z } from "zod";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
const AddressModeEnum = z.nativeEnum(
const AddressModeEnum = z.enum(
Protobuf.Config.Config_NetworkConfig_AddressMode,
);
const ProtocolFlagsEnum = z.nativeEnum(
const ProtocolFlagsEnum = z.enum(
Protobuf.Config.Config_NetworkConfig_ProtocolFlags,
);
export const NetworkValidationIpV4ConfigSchema = z.object({
ip: z.string().ip(),
gateway: z.string().ip(),
subnet: z.string().ip(),
dns: z.string().ip(),
ip: z.ipv4(),
gateway: z.ipv4(),
subnet: z.ipv4(),
dns: z.ipv4(),
});
export const NetworkValidationSchema = z.object({

62
src/validation/config/position.ts

@ -1,44 +1,22 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsEnum, IsInt } from "class-validator";
const DeprecatedPositionValidationFields = ["gpsEnabled", "gpsAttemptTime"];
export class PositionValidation implements
Omit<
Protobuf.Config.Config_PositionConfig,
keyof Message | (typeof DeprecatedPositionValidationFields)[number]
> {
@IsInt()
positionBroadcastSecs: number;
@IsBoolean()
positionBroadcastSmartEnabled: boolean;
@IsBoolean()
fixedPosition: boolean;
@IsInt()
gpsUpdateInterval: number;
@IsInt()
positionFlags: number;
@IsInt()
rxGpio: number;
@IsInt()
txGpio: number;
@IsInt()
broadcastSmartMinimumDistance: number;
@IsInt()
broadcastSmartMinimumIntervalSecs: number;
@IsInt()
gpsEnGpio: number;
@IsEnum(Protobuf.Config.Config_PositionConfig_GpsMode)
gpsMode: Protobuf.Config.Config_PositionConfig_GpsMode;
}
const GpsModeEnum = z.enum(
Protobuf.Config.Config_PositionConfig_GpsMode,
);
export const PositionValidationSchema = z.object({
positionBroadcastSecs: z.int(),
positionBroadcastSmartEnabled: z.boolean(),
fixedPosition: z.boolean(),
gpsUpdateInterval: z.int(),
positionFlags: z.int(),
rxGpio: z.int(),
txGpio: z.int(),
broadcastSmartMinimumDistance: z.int(),
broadcastSmartMinimumIntervalSecs: z.int(),
gpsEnGpio: z.int(),
gpsMode: GpsModeEnum,
});
export type PositionValidation = z.infer<typeof PositionValidationSchema>;

49
src/validation/config/power.ts

@ -1,35 +1,14 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt, IsNumber, Max, Min } from "class-validator";
export class PowerValidation implements
Omit<
Protobuf.Config.Config_PowerConfig,
keyof Message | "powermonEnables"
> {
@IsBoolean()
isPowerSaving: boolean;
@IsInt()
onBatteryShutdownAfterSecs: number;
@IsNumber()
@Min(2)
@Max(4)
adcMultiplierOverride: number;
@IsInt()
waitBluetoothSecs: number;
@IsInt()
sdsSecs: number;
@IsInt()
lsSecs: number;
@IsInt()
minWakeSecs: number;
@IsInt()
deviceBatteryInaAddress: number;
}
import { z } from "zod/v4";
export const PowerValidationSchema = z.object({
isPowerSaving: z.boolean(),
onBatteryShutdownAfterSecs: z.int(),
adcMultiplierOverride: z.number().min(2).max(4),
waitBluetoothSecs: z.int(),
sdsSecs: z.int(),
lsSecs: z.int(),
minWakeSecs: z.int(),
deviceBatteryInaAddress: z.int(),
});
export type PowerValidation = z.infer<typeof PowerValidationSchema>;

50
src/validation/config/security.ts

@ -1,36 +1,14 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsString } from "class-validator";
export class SecurityValidation implements
Omit<
Protobuf.Config.Config_SecurityConfig,
| keyof Message
| "adminKey"
| "privateKey"
| "publicKey"
> {
@IsBoolean()
adminChannelEnabled: boolean;
@IsString()
adminKey: [string, string, string];
@IsBoolean()
bluetoothLoggingEnabled: boolean;
@IsBoolean()
debugLogApiEnabled: boolean;
@IsBoolean()
isManaged: boolean;
@IsString()
privateKey: string;
@IsString()
publicKey: string;
@IsBoolean()
serialEnabled: boolean;
}
import { z } from "zod/v4";
export const SecurityValidationSchema = z.object({
adminChannelEnabled: z.boolean(),
adminKey: z.string().array().length(3),
bluetoothLoggingEnabled: z.boolean(),
debugLogApiEnabled: z.boolean(),
isManaged: z.boolean(),
privateKey: z.string(),
publicKey: z.string(),
serialEnabled: z.boolean(),
});
export type SecurityValidation = z.infer<typeof SecurityValidationSchema>;

37
src/validation/moduleConfig/ambientLighting.ts

@ -1,24 +1,13 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt } from "class-validator";
export class AmbientLightingValidation implements
Omit<
Protobuf.ModuleConfig.ModuleConfig_AmbientLightingConfig,
keyof Message
> {
@IsBoolean()
ledState: boolean;
@IsInt()
current: number;
@IsInt()
red: number;
@IsInt()
green: number;
@IsInt()
blue: number;
}
import { z } from "zod/v4";
export const AmbientLightingValidationSchema = z.object({
ledState: z.boolean(),
current: z.int(),
red: z.int(),
green: z.int(),
blue: z.int(),
});
export type AmbientLightingValidation = z.infer<
typeof AmbientLightingValidationSchema
>;

38
src/validation/moduleConfig/audio.ts

@ -1,28 +1,18 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsEnum, IsInt } from "class-validator";
export class AudioValidation
implements
Omit<Protobuf.ModuleConfig.ModuleConfig_AudioConfig, keyof Message> {
@IsBoolean()
codec2Enabled: boolean;
const Audio_BaudEnum = z.enum(
Protobuf.ModuleConfig.ModuleConfig_AudioConfig_Audio_Baud,
);
@IsInt()
pttPin: number;
export const AudioValidationSchema = z.object({
codec2Enabled: z.boolean(),
pttPin: z.int(),
bitrate: Audio_BaudEnum,
i2sWs: z.int(),
i2sSd: z.int(),
i2sDin: z.int(),
i2sSck: z.int(),
});
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_AudioConfig_Audio_Baud)
bitrate: Protobuf.ModuleConfig.ModuleConfig_AudioConfig_Audio_Baud;
@IsInt()
i2sWs: number;
@IsInt()
i2sSd: number;
@IsInt()
i2sDin: number;
@IsInt()
i2sSck: number;
}
export type AudioValidation = z.infer<typeof AudioValidationSchema>;

65
src/validation/moduleConfig/cannedMessage.ts

@ -1,45 +1,24 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsEnum, IsInt, Length } from "class-validator";
export class CannedMessageValidation implements
Omit<
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig,
keyof Message
> {
@IsBoolean()
rotary1Enabled: boolean;
@IsInt()
inputbrokerPinA: number;
@IsInt()
inputbrokerPinB: number;
@IsInt()
inputbrokerPinPress: number;
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
inputbrokerEventCw:
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
inputbrokerEventCcw:
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
inputbrokerEventPress:
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
@IsBoolean()
updown1Enabled: boolean;
@IsBoolean()
enabled: boolean;
@Length(2, 30)
allowInputSource: string;
@IsBoolean()
sendBell: boolean;
}
const InputEventCharEnum = z.enum(
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar,
);
export const CannedMessageValidationSchema = z.object({
rotary1Enabled: z.boolean(),
inputbrokerPinA: z.int(),
inputbrokerPinB: z.int(),
inputbrokerPinPress: z.int(),
inputbrokerEventCw: InputEventCharEnum,
inputbrokerEventCcw: InputEventCharEnum,
inputbrokerEventPress: InputEventCharEnum,
updown1Enabled: z.boolean(),
enabled: z.boolean(),
allowInputSource: z.string().min(2).max(30),
sendBell: z.boolean(),
});
export type CannedMessageValidation = z.infer<
typeof CannedMessageValidationSchema
>;

49
src/validation/moduleConfig/detectionSensor.ts

@ -1,33 +1,16 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt, Length } from "class-validator";
export class DetectionSensorValidation implements
Omit<
Protobuf.ModuleConfig.ModuleConfig_DetectionSensorConfig,
keyof Message
> {
@IsBoolean()
enabled: boolean;
@IsInt()
minimumBroadcastSecs: number;
@IsInt()
stateBroadcastSecs: number;
@IsBoolean()
sendBell: boolean;
@Length(0, 20)
name: string;
@IsInt()
monitorPin: number;
@IsBoolean()
detectionTriggeredHigh: boolean;
@IsBoolean()
usePullup: boolean;
}
import { z } from "zod/v4";
export const DetectionSensorValidationSchema = z.object({
enabled: z.boolean(),
minimumBroadcastSecs: z.int(),
stateBroadcastSecs: z.int(),
sendBell: z.boolean(),
name: z.string().min(0).max(20),
monitorPin: z.int(),
detectionTriggeredHigh: z.boolean(),
usePullup: z.boolean(),
});
export type DetectionSensorValidation = z.infer<
typeof DetectionSensorValidationSchema
>;

77
src/validation/moduleConfig/externalNotification.ts

@ -1,54 +1,23 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt } from "class-validator";
export class ExternalNotificationValidation implements
Omit<
Protobuf.ModuleConfig.ModuleConfig_ExternalNotificationConfig,
keyof Message
> {
@IsBoolean()
enabled: boolean;
@IsInt()
outputMs: number;
@IsInt()
output: number;
@IsInt()
outputVibra: number;
@IsInt()
outputBuzzer: number;
@IsBoolean()
active: boolean;
@IsBoolean()
alertMessage: boolean;
@IsBoolean()
alertMessageVibra: boolean;
@IsBoolean()
alertMessageBuzzer: boolean;
@IsBoolean()
alertBell: boolean;
@IsBoolean()
alertBellVibra: boolean;
@IsBoolean()
alertBellBuzzer: boolean;
@IsBoolean()
usePwm: boolean;
@IsInt()
nagTimeout: number;
@IsBoolean()
useI2sAsBuzzer: boolean;
}
import { z } from "zod/v4";
export const DetectionSensorValidationSchema = z.object({
enabled: z.boolean(),
outputMs: z.int(),
output: z.int(),
outputVibra: z.int(),
outputBuzzer: z.int(),
active: z.boolean(),
alertMessage: z.boolean(),
alertMessageVibra: z.boolean(),
alertMessageBuzzer: z.boolean(),
alertBell: z.boolean(),
alertBellVibra: z.boolean(),
alertBellBuzzer: z.boolean(),
usePwm: z.boolean(),
nagTimeout: z.int(),
useI2sAsBuzzer: z.boolean(),
});
export type DetectionSensorValidation = z.infer<
typeof DetectionSensorValidationSchema
>;

81
src/validation/moduleConfig/mqtt.ts

@ -1,59 +1,22 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import {
IsBoolean,
IsNumber,
IsOptional,
IsString,
Length,
} from "class-validator";
export class MqttValidation implements
Omit<
Protobuf.ModuleConfig.ModuleConfig_MQTTConfig,
keyof Message | "mapReportSettings"
> {
@IsBoolean()
enabled: boolean;
@Length(0, 30)
address: string;
@Length(0, 30)
username: string;
@Length(0, 30)
password: string;
@IsBoolean()
encryptionEnabled: boolean;
@IsBoolean()
jsonEnabled: boolean;
@IsBoolean()
tlsEnabled: boolean;
@IsString()
root: string;
@IsBoolean()
proxyToClientEnabled: boolean;
@IsBoolean()
mapReportingEnabled: boolean;
mapReportSettings: MqttValidationMapReportSettings;
}
export class MqttValidationMapReportSettings
implements
Omit<Protobuf.ModuleConfig.ModuleConfig_MapReportSettings, keyof Message> {
@IsNumber()
@IsOptional()
publishIntervalSecs: number;
@IsNumber()
@IsOptional()
positionPrecision: number;
}
import { z } from "zod/v4";
export const MqttValidationMapReportSettingsSchema = z.object({
publishIntervalSecs: z.number().optional(),
positionPrecision: z.number().optional(),
});
export const MqttValidationSchema = z.object({
enabled: z.boolean(),
address: z.string().min(0).max(30),
username: z.string().min(0).max(30),
password: z.string().min(0).max(30),
encryptionEnabled: z.boolean(),
jsonEnabled: z.boolean(),
tlsEnabled: z.boolean(),
root: z.string(),
proxyToClientEnabled: z.boolean(),
mapReportingEnabled: z.boolean(),
mapReportSettings: MqttValidationMapReportSettingsSchema,
});
export type MqttValidation = z.infer<typeof MqttValidationSchema>;

19
src/validation/moduleConfig/neighborInfo.ts

@ -1,13 +1,10 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt } from "class-validator";
import { z } from "zod/v4";
export class NeighborInfoValidation
implements
Omit<Protobuf.ModuleConfig.ModuleConfig_NeighborInfoConfig, keyof Message> {
@IsBoolean()
enabled: boolean;
export const NeighborInfoValidationSchema = z.object({
enabled: z.boolean(),
updateInterval: z.int(),
});
@IsInt()
updateInterval: number;
}
export type NeighborInfoValidation = z.infer<
typeof NeighborInfoValidationSchema
>;

25
src/validation/moduleConfig/paxcounter.ts

@ -1,19 +1,10 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt } from "class-validator";
import { z } from "zod/v4";
export class PaxcounterValidation
implements
Omit<Protobuf.ModuleConfig.ModuleConfig_PaxcounterConfig, keyof Message> {
@IsBoolean()
enabled: boolean;
export const PaxcounterValidationSchema = z.object({
enabled: z.boolean(),
paxcounterUpdateInterval: z.int(),
bleThreshold: z.int(),
wifiThreshold: z.int(),
});
@IsInt()
paxcounterUpdateInterval: number;
@IsInt()
bleThreshold: number;
@IsInt()
wifiThreshold: number;
}
export type PaxcounterValidation = z.infer<typeof PaxcounterValidationSchema>;

21
src/validation/moduleConfig/rangeTest.ts

@ -1,16 +1,9 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt } from "class-validator";
import { z } from "zod/v4";
export class RangeTestValidation
implements
Omit<Protobuf.ModuleConfig.ModuleConfig_RangeTestConfig, keyof Message> {
@IsBoolean()
enabled: boolean;
export const RangeTestValidationSchema = z.object({
enabled: z.boolean(),
sender: z.int(),
save: z.boolean(),
});
@IsInt()
sender: number;
@IsBoolean()
save: boolean;
}
export type RangeTestValidation = z.infer<typeof RangeTestValidationSchema>;

49
src/validation/moduleConfig/serial.ts

@ -1,31 +1,22 @@
import type { Message } from "@bufbuild/protobuf";
import { z } from "zod/v4";
import { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsEnum, IsInt } from "class-validator";
export class SerialValidation
implements
Omit<Protobuf.ModuleConfig.ModuleConfig_SerialConfig, keyof Message> {
@IsBoolean()
enabled: boolean;
@IsBoolean()
echo: boolean;
@IsInt()
rxd: number;
@IsInt()
txd: number;
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_SerialConfig_Serial_Baud)
baud: Protobuf.ModuleConfig.ModuleConfig_SerialConfig_Serial_Baud;
@IsInt()
timeout: number;
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_SerialConfig_Serial_Mode)
mode: Protobuf.ModuleConfig.ModuleConfig_SerialConfig_Serial_Mode;
@IsBoolean()
overrideConsoleSerialPort: boolean;
}
const Serial_BaudEnum = z.enum(
Protobuf.ModuleConfig.ModuleConfig_SerialConfig_Serial_Baud,
);
const Serial_ModeEnum = z.enum(
Protobuf.ModuleConfig.ModuleConfig_SerialConfig_Serial_Mode,
);
export const SerialValidationSchema = z.object({
enabled: z.boolean(),
echo: z.boolean(),
rxd: z.int(),
txd: z.int(),
baud: Serial_BaudEnum,
timeout: z.int(),
mode: Serial_ModeEnum,
overrideConsoleSerialPort: z.boolean(),
});
export type SerialValidation = z.infer<typeof SerialValidationSchema>;

37
src/validation/moduleConfig/storeForward.ts

@ -1,24 +1,13 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt } from "class-validator";
export class StoreForwardValidation implements
Omit<
Protobuf.ModuleConfig.ModuleConfig_StoreForwardConfig,
keyof Message | "isServer"
> {
@IsBoolean()
enabled: boolean;
@IsBoolean()
heartbeat: boolean;
@IsInt()
records: number;
@IsInt()
historyReturnMax: number;
@IsInt()
historyReturnWindow: number;
}
import { z } from "zod/v4";
export const StoreForwardValidationSchema = z.object({
enabled: z.boolean(),
heartbeat: z.boolean(),
records: z.int(),
historyReturnMax: z.int(),
historyReturnWindow: z.int(),
});
export type StoreForwardValidation = z.infer<
typeof StoreForwardValidationSchema
>;

55
src/validation/moduleConfig/telemetry.ts

@ -1,37 +1,18 @@
import type { Message } from "@bufbuild/protobuf";
import type { Protobuf } from "@meshtastic/core";
import { IsBoolean, IsInt } from "class-validator";
export class TelemetryValidation
implements
Omit<Protobuf.ModuleConfig.ModuleConfig_TelemetryConfig, keyof Message> {
@IsInt()
deviceUpdateInterval: number;
@IsInt()
environmentUpdateInterval: number;
@IsBoolean()
environmentMeasurementEnabled: boolean;
@IsBoolean()
environmentScreenEnabled: boolean;
@IsBoolean()
environmentDisplayFahrenheit: boolean;
@IsBoolean()
airQualityEnabled: boolean;
@IsInt()
airQualityInterval: number;
@IsBoolean()
powerMeasurementEnabled: boolean;
@IsInt()
powerUpdateInterval: number;
@IsBoolean()
powerScreenEnabled: boolean;
}
import { z } from "zod/v4";
export const StoreForwardValidationSchema = z.object({
deviceUpdateInterval: z.int(),
environmentUpdateInterval: z.int(),
environmentMeasurementEnabled: z.boolean(),
environmentScreenEnabled: z.boolean(),
environmentDisplayFahrenheit: z.boolean(),
airQualityEnabled: z.boolean(),
airQualityInterval: z.int(),
powerMeasurementEnabled: z.boolean(),
powerUpdateInterval: z.int(),
powerScreenEnabled: z.boolean(),
});
export type StoreForwardValidation = z.infer<
typeof StoreForwardValidationSchema
>;

30
src/validation/rasterSource.ts

@ -1,22 +1,14 @@
import { IsArray, IsBoolean, IsNumber, IsString, IsUrl } from "class-validator";
import { z } from "zod/v4";
import type { RasterSource } from "@core/stores/appStore.ts";
export const MapValidation_RasterSourcesSchema = z.object({
enabled: z.boolean(),
title: z.string(),
tiles: z.url(),
tileSize: z.number(),
});
export class MapValidation {
@IsArray()
rasterSources: MapValidation_RasterSources[];
}
export const MapValidationSchema = z.object({
rasterSources: MapValidation_RasterSourcesSchema.array(),
});
export class MapValidation_RasterSources implements RasterSource {
@IsBoolean()
enabled: boolean;
@IsString()
title: string;
@IsUrl()
tiles: string;
@IsNumber()
tileSize: number;
}
export type MapValidation = z.infer<typeof MapValidationSchema>;

4
src/validation/validate.ts

@ -1,7 +1,7 @@
import { ZodError, ZodSchema } from "zod";
import { ZodError, ZodType } from "zod/v4";
export function validateSchema<T>(
schema: ZodSchema<T>,
schema: ZodType<T>,
data: unknown,
): { success: true; data: T } | { success: false; errors: ZodError["issues"] } {
const result = schema.safeParse(data);

Loading…
Cancel
Save