//go:build js && wasm package hp_ipn import ( "errors" "syscall/js" ) // Represents the options needed to initialize the TsWasmNet module. type TsWasmNetOptions struct { // Tailscale control URL, e.g., "https://controlplane.tailscale.com" ControlURL string // Pre-authentication key for the Tailnet PreAuthKey string // Optional hostname, autogenerated if not provided. Hostname string } // Parses the provided JS object to validate and extract the TsWasmNetOptions. func ParseTsWasmNetOptions(obj js.Value) (*TsWasmNetOptions, error) { if obj.IsUndefined() || obj.IsNull() { return nil, errors.New("TsWasmNetOptions cannot be undefined or null") } cUrl := safeString("ControlURL", obj) preAuthKey := safeString("PreAuthKey", obj) hostname := safeString("Hostname", obj) if cUrl == "" || preAuthKey == "" || hostname == "" { return nil, errors.New("missing required fields in TsWasmNetOptions") } return &TsWasmNetOptions{ ControlURL: cUrl, PreAuthKey: preAuthKey, Hostname: hostname, }, nil } // Options passed from the JS side to pass data to xterm.js. type SSHXtermConfig struct { Timeout int // Timeout in seconds for the PTY connection. Rows int // Number of rows in the PTY. Cols int // Number of columns in the PTY. OnStdout func(data js.Value) // Fires when the PTY has output. OnStderr func(error js.Value) // Fires when the PTY has an error. OnStdin js.Value // Passes a function to the JS side to provide input. OnConnect func() // Fires when the PTY is opened. OnDisconnect func() // Fires when the PTY is closed. } // Parses the provided JS object to validate and extract SSHXtermConfig. func ParseSSHXtermConfig(obj js.Value) (*SSHXtermConfig, error) { if obj.IsUndefined() || obj.IsNull() { return nil, errors.New("SSHXtermConfig cannot be undefined or null") } timeout := safeInt("timeout", obj) rows := safeInt("rows", obj) cols := safeInt("cols", obj) if rows <= 0 || cols <= 0 { return nil, errors.New("`rows` and `cols` must be positive integers") } if timeout <= 0 { timeout = 30 // Default timeout to 30 seconds if not specified } config := &SSHXtermConfig{ Timeout: timeout, Rows: rows, Cols: cols, } onStdout := obj.Get("onStdout") if onStdout.IsUndefined() || onStdout.IsNull() || (onStdout.Type() != js.TypeFunction) { return nil, errors.New("`onStdout` is required and must be a function") } config.OnStdout = func(data js.Value) { onStdout.Invoke(data) } onStderr := obj.Get("onStderr") if onStderr.IsUndefined() || onStderr.IsNull() || (onStderr.Type() != js.TypeFunction) { return nil, errors.New("`onStderr` is required and must be a function") } config.OnStderr = func(error js.Value) { onStderr.Invoke(error) } onStdin := obj.Get("onStdin") if onStdin.IsUndefined() || onStdin.IsNull() || (onStdin.Type() != js.TypeFunction) { return nil, errors.New("`onStdin` is required and must be a function") } config.OnStdin = onStdin onConnect := obj.Get("onConnect") if onConnect.IsUndefined() || onConnect.IsNull() || (onConnect.Type() != js.TypeFunction) { return nil, errors.New("`onConnect` is required and must be a function") } config.OnConnect = func() { onConnect.Invoke() } onDisconnect := obj.Get("onDisconnect") if onDisconnect.IsUndefined() || onDisconnect.IsNull() || (onDisconnect.Type() != js.TypeFunction) { return nil, errors.New("`onDisconnect` is required and must be a function") } config.OnDisconnect = func() { onDisconnect.Invoke() } return config, nil } // Retrieves a string value from a JS object safely. func safeString(key string, obj js.Value) string { if obj.IsUndefined() || obj.IsNull() { return "" } val := obj.Get(key) if val.IsUndefined() || val.IsNull() { return "" } return val.String() } // Retrieves an integer value from a JS object safely. func safeInt(key string, obj js.Value) int { if obj.IsUndefined() || obj.IsNull() { return 0 } val := obj.Get(key) if val.IsUndefined() || val.IsNull() { return 0 } return val.Int() }