app

package module
v0.11.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package app hosts an alacris-go live application in a native OS webview.

The live protocol does not change. Go still renders elements, patches props over SSE, and receives component events over POST. This package is a host for that model: it serves the same http.Handler on a loopback address and opens the operating system's webview onto it. There is no JavaScript binding layer, no generated TypeScript, and no second way to talk to Go. Native capabilities (dialogs, menus, the filesystem, notifications) are ordinary Go function calls, typically from a live.On handler or a menu callback.

app.Run(app.Options{
    Title:   "Board",
    Width:   1100,
    Height:  800,
    Handler: mux,
    Menu:    app.DefaultMenu(),
})

Build tags

Opening a window requires a binary built with `-tags desktop`. That pulls CGO and the OS webview (WKWebView, WebView2, WebKitGTK). Without the tag, Listen still works — it is ordinary HTTP — and Run returns ErrNoDesktop.

Host token

EventSource requires an HTTP family URL, so the webview cannot use a custom scheme. Open binds 127.0.0.1 and issues a random host token: the first navigation carries it as a query parameter, the gate swaps it for an HttpOnly cookie and redirects. Another local process that can reach the port cannot create a session without that token. Listen, used by tests, does not install the gate. The live cookie is still required.

Index

Constants

This section is empty.

Variables

View Source
var ErrAlreadyRunning = errors.New("app: another instance is running")

ErrAlreadyRunning is returned by Run when SingleInstance is set and another process of this app holds the lock.

View Source
var ErrCanceled = errors.New("app: canceled")

ErrCanceled is returned by a dialog when the user dismissed it.

View Source
var ErrNoDesktop = errors.New("app: this binary was built without desktop support; rebuild with -tags desktop")

ErrNoDesktop is returned by Run when the binary was not built with `-tags desktop`. Listen does not need the tag.

View Source
var ErrNoShortcut = errors.New("app: global shortcuts are not available")

ErrNoShortcut means this OS cannot register a global hotkey.

Functions

func CacheDir

func CacheDir(identifier string) (string, error)

CacheDir is the per-app directory for disposable files.

func Confirm

func Confirm(ctx context.Context, title, text string) (bool, error)

Confirm asks a yes/no question. false, nil means the user chose No.

func DataDir

func DataDir(identifier string) (string, error)

DataDir is the per-app directory for durable files (config, lock, sockets). identifier is a reverse-DNS id, the same value as Options.Identifier.

func FinishPendingUpdate

func FinishPendingUpdate() error

FinishPendingUpdate applies a parked `exe.new` from a previous Apply that could not replace a locked Windows binary. Run calls it. It is safe to call at the start of main.

func Message

func Message(ctx context.Context, title, text string) error

Message shows an informational dialog with an OK button.

func Notify

func Notify(ctx context.Context, n Notification) error

Notify shows an OS notification.

func OpenFile

func OpenFile(ctx context.Context, dlg FileDialog) (string, error)

OpenFile asks the user to pick an existing file. The zero FileDialog offers every file. ErrCanceled means the user dismissed the dialog.

func OpenURL

func OpenURL(ctx context.Context, raw string) error

OpenURL opens raw in the user's default handler. http, https, mailto, and registered app schemes are accepted; file, network-share and script schemes are refused, as is anything that is not a syntactically valid URL.

func PlatformKey

func PlatformKey() string

PlatformKey is the map key for this binary: GOOS-GOARCH, e.g. darwin-arm64.

func ReadClipboard

func ReadClipboard(ctx context.Context) (string, error)

ReadClipboard returns the current OS clipboard text.

func Relaunch

func Relaunch() error

Relaunch starts a new copy of this executable with the same arguments and exits. On Windows, if a `.new` file is parked next to the running exe (Apply could not replace a locked file), that file is swapped in first.

func RevealInFileManager

func RevealInFileManager(ctx context.Context, path string) error

RevealInFileManager shows path in the OS file manager.

func Run

func Run(opts Options) error

Run listens on loopback, opens a native window onto the handler, and blocks until the window closes.

func SaveAs

func SaveAs(ctx context.Context, dlg FileDialog) (string, error)

SaveAs is SaveFile with a title and default filename.

func SaveFile

func SaveFile(ctx context.Context, filters ...FileFilter) (string, error)

SaveFile asks the user where to write a file.

func SignArtifact

func SignArtifact(priv ed25519.PrivateKey, artifact []byte) string

SignArtifact returns the base64 signature to put in a Manifest. The matching public key is what the app embeds.

func Verify

func Verify(pub ed25519.PublicKey, artifact []byte, sigB64 string) error

Verify reports whether sigB64 is an ed25519 signature of artifact under pub.

func WriteClipboard

func WriteClipboard(ctx context.Context, text string) error

WriteClipboard puts text on the OS clipboard.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

An App owns the loopback host and, once Open has run, one or more windows.

func New

func New(opts Options) *App

New prepares an App. It does not listen or open a window.

func (*App) Host

func (a *App) Host() *Host

Host is the loopback server Open created, or nil.

func (*App) NewWindow

func (a *App) NewWindow() (*Window, error)

NewWindow opens another window onto the same host. Open must have run.

func (*App) Open

func (a *App) Open() (*Window, error)

Open starts the gated loopback server and creates the first window without entering the event loop. A second Open returns the existing first window; use NewWindow for another.

func (*App) Run

func (a *App) Run() error

Run opens a window if needed and blocks in the native event loop.

func (*App) Window

func (a *App) Window() *Window

Window is the window Open created, or nil.

type Appearance

type Appearance int

Appearance is the window chrome colour scheme. The page still follows whatever Config.Theme (or the OS) says; this only hints the title bar.

const (
	// AppearanceSystem follows the OS. It is the default.
	AppearanceSystem Appearance = iota
	AppearanceLight
	AppearanceDark
)

type FileDialog

type FileDialog struct {
	Title    string
	Filename string
	Filters  []FileFilter
}

A FileDialog configures OpenFile or SaveFile.

type FileFilter

type FileFilter struct {
	Name string // "JSON"
	Ext  string // ".json"
}

FileFilter names one extension the file dialog should offer.

type Host

type Host struct {
	// contains filtered or unexported fields
}

A Host is the loopback HTTP server Run puts behind the webview.

Listen is the testable half of the host: it does not need a display or `-tags desktop`. The caller must Shutdown. Listen does not install the host-token gate; Open does, so a window is the only client that can create a session.

func Listen

func Listen(opts Options) (*Host, error)

Listen serves opts.Handler on a loopback address and returns the bound host. Tests use this. Run/Open call listen with the host-token gate on.

func (*Host) BootstrapURL

func (h *Host) BootstrapURL(path string) string

BootstrapURL is the first navigation target. When the host is gated it carries the one-shot token as a query parameter; the gate swaps that for an HttpOnly cookie and redirects, so EventSource never sees the token.

func (*Host) Hostport

func (h *Host) Hostport() string

Hostport is the Host header value that will be accepted, host:port.

func (*Host) Shutdown

func (h *Host) Shutdown(ctx context.Context) error

Shutdown closes the listener and waits for in-flight requests, the same contract as http.Server.Shutdown.

A live EventSource is a request that never ends on its own, so Shutdown with a background context would wait forever and the process would sit in the dock until it was force-quit. The caller must bound ctx; leftover streams are then forced closed so their handlers return.

func (*Host) URL

func (h *Host) URL() string

URL is the origin the webview should navigate to, with no path.

type Manifest

type Manifest struct {
	Version   string                    `json:"version"`
	Notes     string                    `json:"notes,omitempty"`
	PubDate   string                    `json:"pub_date,omitempty"`
	Platforms map[string]PlatformUpdate `json:"platforms"`
}

Manifest is the JSON an updater endpoint serves. The shape matches Tauri's updater so a GitHub Release can host one file both tools read.

{
  "version": "0.2.0",
  "notes": "…",
  "pub_date": "2026-08-17T12:00:00Z",
  "platforms": {
    "darwin-arm64": {
      "url": "https://example/Board_0.2.0_darwin-arm64.tar.gz",
      "signature": "<base64 ed25519 of the artifact bytes>"
    }
  }
}
type Menu struct {
	Items []MenuItem
}

A Menu is a native menu bar.

func DefaultMenu

func DefaultMenu() *Menu

DefaultMenu is Quit under File, plus the Edit menu a text field needs.

type MenuItem struct {
	Title string
	Keys  string // "CmdOrCtrl+E", "CmdOrCtrl+Shift+N"
	Role  Role
	Do    func(w *Window)
	Items []MenuItem
}

A MenuItem is one entry, a separator, or a submenu.

Do runs on the UI thread. It may call SaveFile, patch a live session, or Close the window. It is ignored when Role is not RoleNone.

func EditMenu

func EditMenu() MenuItem

EditMenu is Cut/Copy/Paste/Select All, as one top-level item.

type Notification

type Notification struct {
	Title string
	Body  string
}

A Notification is a desktop banner. It does not need `-tags desktop`.

type Options

type Options struct {
	// Title is the window title. Defaults to "alacris".
	Title string

	// Width and Height are the initial content size in pixels.
	// They default to 800×600.
	Width  int
	Height int

	// MinWidth and MinHeight bound shrinking. Zero means no minimum.
	MinWidth  int
	MinHeight int

	// FixedSize prevents the user from resizing the window.
	FixedSize bool

	// Handler is the same mux a browser build would ListenAndServe.
	// Required.
	Handler http.Handler

	// Path is the URL path the webview opens, relative to the loopback
	// origin. Defaults to "/".
	Path string

	// Addr is the loopback address to bind. Empty means 127.0.0.1:0
	// (a free port). Only loopback hosts are accepted; 0.0.0.0 is refused.
	Addr string

	// Menu is installed as the native menu bar on macOS, Windows, and
	// Linux. Nil means no menu; DefaultMenu is the usual Edit/Quit set.
	Menu *Menu

	// Appearance hints the title bar. The default follows the OS.
	Appearance Appearance

	// Dev opens the webview inspector.
	Dev bool

	// OnReady runs after the window exists and the loopback server is
	// listening, immediately before the native event loop blocks. Window
	// methods that do not need Dispatch (SetTitle, SetSize, Close) are
	// safe here.
	OnReady func(*Window)

	// X and Y are the initial window origin in screen pixels. Ignored
	// when Center is true. Both zero means the OS picks.
	X, Y int

	// Center places the window on the primary display. Overrides X and Y.
	Center bool

	// MaxWidth and MaxHeight bound growing. Zero means no maximum.
	MaxWidth  int
	MaxHeight int

	// Fullscreen opens the window in the OS full-screen space.
	Fullscreen bool

	// Undecorated hides the native title bar. Equivalent to
	// Titlebar: TitlebarHidden, which is the clearer spelling.
	Undecorated bool

	// Titlebar chooses how the title bar is drawn. The zero value is the OS
	// one, so this is opt-in.
	Titlebar Titlebar

	// AlwaysOnTop keeps the window above others.
	AlwaysOnTop bool

	// Hidden opens the window without showing it (a tray-only start).
	Hidden bool

	// Identifier is the reverse-DNS id used for single-instance locking,
	// data directories, and deep-link registration. Required when
	// SingleInstance is true.
	Identifier string

	// SingleInstance refuses a second process and forwards its arguments
	// to OnSecondInstance on the first.
	SingleInstance bool

	// OnSecondInstance runs in the first process when another launch is
	// refused. Args are the second process's os.Args[1:].
	OnSecondInstance func(args []string)

	// DeepLinkScheme registers an URL scheme (no "://") the OS should
	// deliver to this app. OnDeepLink receives the full URL.
	DeepLinkScheme string

	// OnDeepLink runs when the OS delivers a matching URL. Also invoked
	// for a second-instance launch whose args look like a URL.
	OnDeepLink func(url string)

	// Tray, if set, installs a status-item / notification-area icon.
	Tray *Tray

	// OnClose runs as the loopback host is coming down, after the last
	// window has already gone. Use it to drop long-lived connections
	// (a live EventSource, a second listener) so Shutdown does not wait
	// on them. The return is kept for the documented cancel, but by this
	// point the event loop has ended and a false cannot keep the window.
	OnClose func() bool
}

Options configure a desktop window around an http.Handler.

type PlatformUpdate

type PlatformUpdate struct {
	URL       string `json:"url"`
	Signature string `json:"signature"`
}

PlatformUpdate is one OS/arch artifact.

type Role

type Role int

Role is a standard menu action the OS already knows how to perform.

const (
	RoleNone Role = iota
	RoleQuit
	RoleCut
	RoleCopy
	RolePaste
	RoleSelectAll
	RoleSeparator
)

type Titlebar added in v0.8.0

type Titlebar int

Titlebar is how the window's title bar is drawn.

The default is the OS one. The other two exist because an application whose own surface runs to the top edge looks wrong underneath a bar the OS painted a different colour, and there is no way to tint that bar: on macOS it is AppKit's, in whatever grey the current appearance says.

const (
	// TitlebarNative is the OS title bar, drawn by the OS. The default.
	TitlebarNative Titlebar = iota

	// TitlebarInset keeps the window buttons and lets the page draw behind
	// them. Content runs to the top edge and the bar is whatever the page
	// paints there; dragging and the buttons stay native.
	//
	// This is what a modern desktop application usually wants. On macOS it is
	// a transparent title bar over a full-size content view, so the traffic
	// lights float above the page. Windows and Linux have no equivalent of
	// that arrangement, so they fall back to TitlebarHidden and the page is
	// expected to draw its own buttons.
	TitlebarInset

	// TitlebarHidden removes the title bar altogether. The page draws its own,
	// and BeginDrag moves the window.
	TitlebarHidden
)

type Tray

type Tray struct {
	// Title is shown when the OS cannot draw an icon (macOS extra, Linux).
	Title string
	// Tooltip is the hover text.
	Tooltip string
	Menu    *Menu
}

A Tray is a status-item / notification-area icon. Menu items with Do run as Go callbacks, the same as the window menu.

type Update

type Update struct {
	Version   string
	Notes     string
	URL       string
	Signature string
	Current   string
}

An Update is a verified, newer build ready to download.

type Updater

type Updater struct {
	// Endpoint is the URL of a Manifest JSON file.
	Endpoint string
	// PublicKey verifies PlatformUpdate.Signature. Required.
	PublicKey ed25519.PublicKey
	// Current is this binary's version. Compared as a dotted triple when
	// both sides look like semver; otherwise string inequality is enough
	// to offer the update.
	Current string
	// HTTP is the client used to fetch. Defaults to http.DefaultClient.
	HTTP *http.Client
	// ApplyTo is the path replaced on Apply. Empty means os.Executable.
	ApplyTo string
}

Updater checks an HTTP endpoint for a newer signed artifact.

func (Updater) Apply

func (u Updater) Apply(ctx context.Context, upd *Update) error

Apply downloads the artifact, verifies the ed25519 signature, and replaces the running binary. The process is not restarted; call ApplyAndRelaunch (or Relaunch after Apply) to exec the new file. On Windows, a locked executable is parked as `<exe>.new` and swapped in by Relaunch.

func (Updater) ApplyAndRelaunch

func (u Updater) ApplyAndRelaunch(ctx context.Context, upd *Update) error

ApplyAndRelaunch is Apply followed by Relaunch. On success this process is replaced or exited.

func (Updater) Check

func (u Updater) Check(ctx context.Context) (*Update, error)

Check fetches the manifest and reports whether a newer signed artifact exists for this platform. A nil Update means the running version is current. Signature is not verified until Apply downloads the bytes.

type Window

type Window struct {
	// contains filtered or unexported fields
}

A Window is one native webview. An App may open more than one; Run blocks on the first until it closes.

func (*Window) BeginDrag added in v0.8.0

func (w *Window) BeginDrag()

BeginDrag starts moving the window, as though the pointer had grabbed a title bar.

It is for a page that draws its own title bar: call it from a pointerdown in the region that should behave like one, over the live layer. The OS then runs the drag, so the window keeps up with the pointer rather than chasing it through a round trip per frame.

It only does anything while a mouse button is actually down, because every platform implements it by handing the current event back to the window manager.

func (*Window) Center

func (w *Window) Center()

Center places the window on the primary display.

func (*Window) Close

func (w *Window) Close()

Close terminates this window. Closing the last window ends Run.

func (*Window) Focus

func (w *Window) Focus()

Focus brings the window to the front.

func (*Window) Fullscreen

func (w *Window) Fullscreen()

Fullscreen enters the OS full-screen space.

func (*Window) Hide

func (w *Window) Hide()

Hide removes the window from the screen without destroying it.

func (*Window) Maximize

func (w *Window) Maximize()

Maximize fills the work area. Unmaximize restores the previous size.

func (*Window) Minimize

func (w *Window) Minimize()

Minimize hides the window in the dock / taskbar.

func (*Window) Position

func (w *Window) Position() (x, y int)

Position is the window's top-left corner, in screen pixels.

func (*Window) RegisterShortcut

func (w *Window) RegisterShortcut(keys string, fn func()) error

RegisterShortcut binds keys (the same grammar as MenuItem.Keys) as a global hotkey while the app is running. Needs `-tags desktop`.

func (*Window) SetAlwaysOnTop

func (w *Window) SetAlwaysOnTop(on bool)

SetAlwaysOnTop keeps the window above others when on is true.

func (*Window) SetBadge

func (w *Window) SetBadge(s string)

func (*Window) SetDecorations

func (w *Window) SetDecorations(on bool)

SetDecorations shows or hides the native title bar.

func (*Window) SetPosition

func (w *Window) SetPosition(x, y int)

SetPosition moves the window's top-left corner, in screen pixels.

func (*Window) SetSize

func (w *Window) SetSize(width, height int)

SetSize updates the content size in pixels.

func (*Window) SetTitle

func (w *Window) SetTitle(title string)

SetTitle updates the native title bar.

func (*Window) SetTitlebar added in v0.8.0

func (w *Window) SetTitlebar(style Titlebar)

SetBadge sets the dock / taskbar badge. Empty clears it. No-op where the OS has no badge. SetTitlebar chooses how the title bar is drawn.

func (*Window) Show

func (w *Window) Show()

Show makes a hidden window visible.

func (*Window) URL

func (w *Window) URL() string

URL is the loopback origin this window was navigated to.

func (*Window) Unfullscreen

func (w *Window) Unfullscreen()

Unfullscreen leaves full-screen.

func (*Window) Unmaximize

func (w *Window) Unmaximize()

Unmaximize restores a maximized window.

func (*Window) UnregisterShortcut

func (w *Window) UnregisterShortcut(keys string) error

UnregisterShortcut drops a previously registered hotkey.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL