9.7 KiB
Wails Go API surface for the React frontend
All bindings live under frontend/bindings/github.com/netbirdio/netbird/client/ui-wails/services/. Import them as:
import { Connection, Peers, Networks, Settings, Profiles, Debug, Update, Forwarding } from "./bindings/github.com/netbirdio/netbird/client/ui-wails/services";
import * as $models from "./bindings/github.com/netbirdio/netbird/client/ui-wails/services/models";
Every method returns $CancellablePromise<T> (Wails3 wrapper around a Promise — call .cancel() to abort the underlying gRPC stream / call).
Push events
Subscribe with the Wails event API: import { Events } from "@wailsio/runtime".
| Event name | Payload type | Fires on |
|---|---|---|
netbird:status |
Status |
Daemon connection-state change (Connected / Connecting / Disconnected / Idle), peer-list change, address change, management/signal flip. Replaces polling. |
netbird:event |
SystemEvent |
One push per daemon-emitted event (DNS/network/auth/connectivity/system). Drives toasts and the event log. |
netbird:update:available |
UpdateAvailable |
Daemon detected a new version. Show the update menu/banner. |
netbird:update:progress |
UpdateProgress |
action:"show" → open the update progress page; action:"hide" → close. |
Calling Peers.Watch() once at boot starts both backend stream loops; both self-restart with backoff on errors.
Connection lifecycle — Connection
Connection.Up(p: UpParams): Promise<void>
Connection.Down(): Promise<void>
Connection.Login(p: LoginParams): Promise<LoginResult>
Connection.WaitSSOLogin(p: WaitSSOParams): Promise<string> // returns email/userInfo
Connection.Logout(p: LogoutParams): Promise<void>
- Up flow: call
Loginfirst; ifLoginResult.needsSsoLogin === trueopenverificationUriCompletein the browser, then callWaitSSOLoginwith{ userCode: LoginResult.userCode, hostname: ... }. Once that resolves callUp. - Down flow: just
Down(). The daemon transitions toIdle.
class LoginParams { profileName, username, managementUrl, setupKey, preSharedKey, hostname, hint: string }
class LoginResult { needsSsoLogin: boolean; userCode, verificationUri, verificationUriComplete: string }
class WaitSSOParams { userCode, hostname: string }
class UpParams { profileName, username: string }
class LogoutParams { profileName, username: string }
Status / peer list — Peers
Peers.Get(): Promise<Status> // one-shot snapshot
Peers.Watch(): Promise<void> // call once at boot to enable push events
class Status {
status: string // "Idle" | "Connecting" | "Connected" | "SessionExpired" (see below)
daemonVersion: string
management: PeerLink
signal: PeerLink
local: LocalPeer
peers: PeerStatus[]
events: SystemEvent[]
}
class PeerLink {
url: string
connected: boolean
}
class LocalPeer {
ip, pubKey, fqdn: string
networks: string[]
}
class PeerStatus {
ip, pubKey, fqdn: string
connStatus: string // "Connected" | "Connecting" | "Idle"
connStatusUpdateUnix: number // unix seconds
relayed: boolean
localIceCandidateType, remoteIceCandidateType: string
localIceCandidateEndpoint, remoteIceCandidateEndpoint: string
bytesRx, bytesTx: number
latencyMs: number
relayAddress: string // populated when relayed
lastHandshakeUnix: number
rosenpassEnabled: boolean
networks: string[]
}
class SystemEvent {
id: string
severity: string // "info" | "warning" | "error" | "critical"
category: string // "network" | "dns" | "authentication" | "connectivity" | "system"
message: string // technical / log message
userMessage: string // human-friendly message — render this
timestamp: number // unix seconds
metadata: Record<string, string>
}
Connection-state values
The Status.status field uses these literal strings (from the daemon):
| Value | Meaning |
|---|---|
"Idle" |
Disconnected — Up not invoked, or Down completed |
"Connecting" |
Up in progress |
"Connected" |
Tunnel up |
"SessionExpired" |
SSO token expired — needs Login again |
(The Fyne UI also reads a synthetic "Error" label for some failed states; check events for details.)
ICE candidate type values
localIceCandidateType / remoteIceCandidateType are pion/ICE strings: "host", "srflx", "prflx", "relay", or "" while connecting.
Networks — Networks
Networks.List(): Promise<Network[]>
Networks.Select(p: SelectNetworksParams): Promise<void>
Networks.Deselect(p: SelectNetworksParams): Promise<void>
class Network {
id, range: string // range is a CIDR
selected: boolean
domains: string[] // empty unless this is a domain network
resolvedIps: Record<string, string[]> // domain -> IPs
}
class SelectNetworksParams {
networkIds: string[]
append: boolean // false = replace selection, true = merge with existing
all: boolean // true = ignore networkIds and target every network (Select-All / Deselect-All)
}
The Fyne UI's All / Overlapping / Exit-node tabs are filters over the same List() result:
- Exit-node:
range === "0.0.0.0/0" || range === "::/0" - Overlapping: client-side detection of CIDR overlap among
rangevalues - All: everything
Forwarding / exposed services — Forwarding
Forwarding.List(): Promise<ForwardingRule[]>
class ForwardingRule {
protocol: string // "tcp" | "udp"
destinationPort: PortInfo
translatedAddress, translatedHostname: string
translatedPort: PortInfo
}
class PortInfo { // exactly one field is populated
port?: number
range?: PortRange
}
class PortRange { start, end: number }
Profiles — Profiles
Profiles.List(username: string): Promise<Profile[]>
Profiles.GetActive(): Promise<ActiveProfile>
Profiles.Switch(p: ProfileRef): Promise<void>
Profiles.Add(p: ProfileRef): Promise<void>
Profiles.Remove(p: ProfileRef): Promise<void>
Profiles.Username(): Promise<string> // current OS username
class Profile { name: string; isActive: boolean }
class ProfileRef { profileName, username: string }
class ActiveProfile { profileName, username: string }
Settings / config — Settings
Settings.GetConfig(p: ConfigParams): Promise<Config>
Settings.SetConfig(p: SetConfigParams): Promise<void>
Settings.GetFeatures(): Promise<Features>
class ConfigParams { profileName, username: string } // identifies which profile's config
class Config {
managementUrl, adminUrl, configFile, logFile, preSharedKey: string
interfaceName: string; wireguardPort, mtu: number
disableAutoConnect, serverSshAllowed: boolean
rosenpassEnabled, rosenpassPermissive: boolean
disableNotifications, lazyConnectionEnabled, blockInbound: boolean
networkMonitor, disableClientRoutes, disableServerRoutes: boolean
disableDns, blockLanAccess: boolean
enableSshRoot, enableSshSftp: boolean
enableSshLocalPortForwarding, enableSshRemotePortForwarding: boolean
disableSshAuth: boolean
sshJwtCacheTtl: number
}
class SetConfigParams {
// identity (always required)
profileName, username: string
// any field below is optional — only the ones you set are pushed to the daemon
managementUrl?, adminUrl?, ...
// ... same shape as Config
}
class Features {
// feature flags from the daemon — hide UI sections when these are true
disableProfiles, disableUpdateSettings, disableNetworks: boolean
}
SetConfig is partial — supply only the fields you want to change, plus profileName + username. Booleans use Go pointer-presence under the hood; on the TS side undefined / missing means "leave as-is".
Debug bundle / log level — Debug
Debug.GetLogLevel(): Promise<LogLevel>
Debug.SetLogLevel(lvl: LogLevel): Promise<void>
Debug.Bundle(p: DebugBundleParams): Promise<DebugBundleResult>
class LogLevel { level: string } // "trace" | "debug" | "info" | "warning" | "error" | "panic"
class DebugBundleParams {
anonymize: boolean
systemInfo: boolean
uploadUrl: string // empty string = no upload
logFileCount: number // 0 = default
}
class DebugBundleResult {
path: string // local path of the generated bundle
uploadedKey: string // populated when uploadUrl was set
uploadFailureReason: string // populated on upload error
}
Update flow — Update
Update.Trigger(): Promise<UpdateResult> // start the install
Update.GetInstallerResult(): Promise<UpdateResult> // poll the install outcome (long-running)
class UpdateResult { success: boolean; errorMsg: string }
class UpdateAvailable { // payload of "netbird:update:available"
version: string
enforced: boolean // true = management server requires it
}
class UpdateProgress { // payload of "netbird:update:progress"
action: string // "show" | "hide"
version: string
}
Typical flow:
- Listen for
"netbird:update:available"→ show the "Update X.Y.Z" affordance. - User clicks → call
Update.Trigger(). - The page that shows the install progress polls
GetInstallerResult()(15-min timeout). Onsuccess: truethe daemon will exit; the app shouldapp.Quit()(or restart). Onsuccess: falseshowerrorMsg.
Toast notifications
The tray sends OS notifications via application/services/notifications automatically for netbird:event events that have userMessage. The frontend doesn't need to do anything for that; the data is also delivered via netbird:event if you want to render an in-window log.