TypeScript client for Tailscale LocalAPI built with Bun.
- Linux support: Unix socket connection to Tailscale daemon
- Full API coverage: status, whois, prefs, DERP map, DNS, metrics, profiles, and more
- Type-safe: Comprehensive TypeScript definitions matching Tailscale API
- Bun-native: Optimized for Bun runtime
bun installimport TailscaleLocalAPI from "./src/index"
const client = new TailscaleLocalAPI()
// Get current status
const status = await client.status()
console.log("Backend state:", status.BackendState)
console.log("Self:", status.self?.dnsName)Uses Unix socket at /var/run/tailscale/tailscaled.sock by default.
const client = new TailscaleLocalAPI({
socketPath: "/var/run/tailscale/tailscaled.sock",
})| Variable | Description |
|---|---|
TAILSCALE_LOCALAPI_SOCKET |
Unix socket path (Linux) |
// Get full status with peers
const status = await client.status()
// Get status without peers (faster)
const status = await client.statusWithoutPeers()// Lookup peer information by IP
const whois = await client.whois("100.x.x.x")
console.log("User:", whois.userProfile.loginName)
console.log("Node:", whois.node.name)// Get current preferences
const prefs = await client.getPrefs()
// Edit preferences
await client.editPrefs({
exitNodeId: "some-node-id",
acceptRoutes: true,
})
// Validate preferences
const validation = await client.checkPrefs(prefs)// Get DERP relay configuration
const derpMap = await client.getDERPMap()
derpMap.regions.forEach((region) => {
console.log(`Region ${region.regionName}: ${region.nodes.length} nodes`)
})// Query DNS
const dnsResult = await client.queryDNS("example.com", "A")
console.log("Resolvers:", dnsResult.resolvers)
// Get system DNS configuration
const dnsConfig = await client.getDNSOSConfig()
console.log("Nameservers:", dnsConfig.nameservers)// Get current profile
const current = await client.getCurrentProfile()
// Get all profiles
const profiles = await client.getProfiles()
// Switch profile
await client.switchProfile("profile-id")// Start interactive login
await client.loginInteractive()
// Logout (may log you out)
await client.logout()
// Reset auth (may require re-authentication)
await client.resetAuth()// Start Tailscale
await client.start({ hostName: "my-device" })
// Reload configuration
const result = await client.reloadConfig()
// Shutdown Tailscale
await client.shutdown()// Check IP forwarding
const ipForwarding = await client.checkIPForwarding()
// Check SO_MARK usage
const soMark = await client.checkSOMarkInUse()Run the test suite to verify functionality:
bun testNote: Tests are designed to work with an active Tailscale daemon and may be skipped if not available.
import {
AccessDeniedError,
PeerNotFoundError,
PreconditionsFailedError,
} from "./src/index"
try {
await client.whois("invalid-ip")
} catch (error) {
if (error instanceof AccessDeniedError) {
console.error("Access denied")
} else if (error instanceof PeerNotFoundError) {
console.error("Peer not found")
} else if (error instanceof PreconditionsFailedError) {
console.error("Preconditions failed")
} else {
console.error("Unknown error:", error)
}
}Run debug.ts to get a comprehensive overview of your Tailscale setup, including status, profiles, preferences, DERP map, and all tailnet devices:
bun debug.tsinterface ClientOptions {
socketPath?: string // Unix socket path (Linux)
timeout?: number // Request timeout in ms (default: 30000)
}