tauri-plugin-network-manager 2.1.1

A Tauri plugin to manage network connections using networkmanager and systemd-networkd.
Documentation
# Tauri Network Manager Plugin

Linux-first Tauri plugin to manage network state, Wi-Fi and VPN through NetworkManager over D-Bus.

## Features

- Read current network state
- List available Wi-Fi networks
- Connect and disconnect Wi-Fi
- List and delete saved Wi-Fi connections
- Enable or disable networking and wireless
- Check wireless adapter availability
- Read network stats and available interfaces
- List VPN profiles
- Read current VPN status
- Connect and disconnect VPN profiles
- Create, update and delete VPN profiles
- Listen to network and VPN change events (`network-changed`, `vpn-changed`, `vpn-connected`, `vpn-disconnected`, `vpn-failed`)

## Requirements

- Linux with NetworkManager running
- Tauri 2
- Rust 1.77.2+

## Installation

### Rust dependency

Add the plugin crate to your Tauri app:

```toml
[dependencies]
tauri-plugin-network-manager = { git = "https://github.com/Vasak-OS/tauri-plugin-network-manager" }
```

Register the plugin in your Tauri builder.

### NPM package

Install the JS guest bindings:

```bash
bun add @vasakgroup/plugin-network-manager
```

## Permissions (Tauri capabilities)

The default permission set includes:

- `network-manager:allow-get-network-state`
- `network-manager:allow-list-wifi-networks`
- `network-manager:allow-rescan-wifi`
- `network-manager:allow-connect-to-wifi`
- `network-manager:allow-disconnect-from-wifi`
- `network-manager:allow-get-saved-wifi-networks`
- `network-manager:allow-delete-wifi-connection`
- `network-manager:allow-toggle-network-state`
- `network-manager:allow-get-wireless-enabled`
- `network-manager:allow-set-wireless-enabled`
- `network-manager:allow-is-wireless-available`
- `network-manager:allow-list-vpn-profiles`
- `network-manager:allow-get-vpn-status`

Mutating VPN operations are intentionally excluded from default permissions.

To enable VPN management operations, add the dedicated permission set:

- `network-manager:vpn_management`

This set includes:

- `network-manager:allow-connect-vpn`
- `network-manager:allow-disconnect-vpn`
- `network-manager:allow-create-vpn-profile`
- `network-manager:allow-update-vpn-profile`
- `network-manager:allow-delete-vpn-profile`

## Types exposed in NPM

The package exports these TypeScript types:

- `NetworkInfo`
- `NetworkStats`
- `WiFiSecurityType`
- `WiFiConnectionConfig` (Rust wire format)
- `ConnectToWifiInput` (frontend-friendly format)
- `ListWifiNetworksOptions`
- `VpnType`
- `VpnConnectionState`
- `VpnProfile`
- `VpnStatus`
- `VpnEventPayload`
- `VpnCreateInput`
- `VpnUpdateInput`
- `NetworkManagerErrorCode`
- `NetworkManagerError`

### Security type values

`WiFiSecurityType` values are:

- `none`
- `wep`
- `wpa-psk`
- `wpa-eap`
- `wpa2-psk`
- `wpa3-psk`

### VPN type values

`VpnType` values are:

- `open-vpn`
- `wire-guard`
- `l2tp`
- `pptp`
- `sstp`
- `ikev2`
- `fortisslvpn`
- `open-connect`
- `generic`

## API reference

### State and scan

- `getCurrentNetworkState(): Promise<NetworkInfo>`
- `listWifiNetworks(options?: ListWifiNetworksOptions): Promise<NetworkInfo[]>`
- `rescanWifi(): Promise<NetworkInfo[]>`
- `getSavedWifiNetworks(): Promise<NetworkInfo[]>`

### Wi-Fi connection management

- `connectToWifi(config: ConnectToWifiInput | WiFiConnectionConfig): Promise<void>`
- `disconnectFromWifi(): Promise<void>`
- `deleteWifiConnection(ssid: string): Promise<void>`

### VPN profile and connection management

- `listVpnProfiles(): Promise<VpnProfile[]>`
- `getVpnStatus(): Promise<VpnStatus>`
- `connectVpn(uuid: string): Promise<void>`
- `disconnectVpn(uuid?: string): Promise<void>`
- `createVpnProfile(config: VpnCreateInput): Promise<VpnProfile>`
- `updateVpnProfile(config: VpnUpdateInput): Promise<VpnProfile>`
- `deleteVpnProfile(uuid: string): Promise<void>`

### Radio and networking toggles

- `toggleNetwork(enabled: boolean): Promise<void>`
- `getWirelessEnabled(): Promise<boolean>`
- `setWirelessEnabled(enabled: boolean): Promise<void>`
- `isWirelessAvailable(): Promise<boolean>`

### Stats

- `getNetworkStats(): Promise<NetworkStats>`
- `getNetworkInterfaces(): Promise<string[]>`

## Usage examples (TypeScript)

### Wi-Fi

```ts
import {
  connectToWifi,
  deleteWifiConnection,
  disconnectFromWifi,
  getCurrentNetworkState,
  getSavedWifiNetworks,
  listWifiNetworks,
  WiFiSecurityType,
} from '@vasakgroup/plugin-network-manager';

async function wifiFlow() {
  const state = await getCurrentNetworkState();
  console.log('Current network:', state);

  const available = await listWifiNetworks();
  console.log('Available Wi-Fi:', available.map((n) => n.ssid));

  await connectToWifi({
    ssid: 'OfficeWiFi',
    password: 'secret-password',
    securityType: WiFiSecurityType.WPA2_PSK,
  });

  const saved = await getSavedWifiNetworks();
  console.log('Saved Wi-Fi:', saved.map((n) => n.ssid));

  await disconnectFromWifi();
  await deleteWifiConnection('OldNetwork');
}

wifiFlow().catch(console.error);
```

### VPN

```ts
import {
  connectVpn,
  createVpnProfile,
  disconnectVpn,
  getVpnStatus,
  listVpnProfiles,
  updateVpnProfile,
  deleteVpnProfile,
} from '@vasakgroup/plugin-network-manager';

async function vpnFlow() {
  const profile = await createVpnProfile({
    id: 'Office VPN',
    vpn_type: 'wire-guard',
    autoconnect: false,
    settings: {
      mtu: '1420',
      remote: 'vpn.example.com:51820',
    },
    secrets: {
      private_key: '***',
    },
  });

  console.log('Created profile:', profile);

  const profiles = await listVpnProfiles();
  console.log('Profiles:', profiles.map((p) => `${p.id} (${p.uuid})`));

  await connectVpn(profile.uuid);
  console.log('VPN status after connect:', await getVpnStatus());

  const updated = await updateVpnProfile({
    uuid: profile.uuid,
    autoconnect: true,
  });
  console.log('Updated profile:', updated);

  await disconnectVpn(profile.uuid);
  await deleteVpnProfile(profile.uuid);
}

vpnFlow().catch(console.error);
```

### Listening to VPN events

```ts
import { listen } from '@tauri-apps/api/event';
import type { VpnEventPayload } from '@vasakgroup/plugin-network-manager';

const unlistenChanged = await listen<VpnEventPayload>('vpn-changed', (event) => {
  console.log('VPN changed:', event.payload.status.state);
});

const unlistenConnected = await listen<VpnEventPayload>('vpn-connected', (event) => {
  console.log('VPN connected:', event.payload.profile?.id);
});

const unlistenFailed = await listen<VpnEventPayload>('vpn-failed', (event) => {
  console.error('VPN failed:', event.payload.reason);
});

// call unlistenChanged(), unlistenConnected(), unlistenFailed() when no longer needed
```

## Typed errors

All exported async functions throw a typed `NetworkManagerError` with a `code` in case of invoke failure.

Common Wi-Fi and generic codes:

- `NOT_INITIALIZED`
- `NO_CONNECTION`
- `PERMISSION_DENIED`
- `UNSUPPORTED_SECURITY`
- `CONNECTION_FAILED`
- `NETWORK_NOT_FOUND`
- `OPERATION_FAILED`

VPN-specific codes:

- `VPN_PROFILE_NOT_FOUND`
- `VPN_ALREADY_CONNECTED`
- `VPN_AUTH_FAILED`
- `VPN_INVALID_CONFIG`
- `VPN_ACTIVATION_FAILED`
- `VPN_PLUGIN_UNAVAILABLE`
- `VPN_NOT_ACTIVE`

Fallback code:

- `UNKNOWN`

## Package exports and types

The package is published with ESM + CJS bundles and declaration files:

- `main`: `./dist-js/index.cjs`
- `module`: `./dist-js/index.js`
- `types`: `./dist-js/index.d.ts`
- `exports.types`: `./dist-js/index.d.ts`
- `exports.import`: `./dist-js/index.js`
- `exports.require`: `./dist-js/index.cjs`

## Notes

- `connectToWifi` accepts both formats:
  - frontend-friendly: `{ securityType: ... }`
  - Rust wire-format: `{ security_type: ... }`
- The wrapper maps frontend input to the command payload expected by Rust.
- `listWifiNetworks` supports cache control:
  - `forceRefresh`: bypasses cache
  - `ttlMs`: cache TTL in milliseconds

## Testing and build

Build package:

```bash
bun run build
```

Run smoke tests:

```bash
bun run test
```