proton

MoonBit bindings for the Proton native desktop runtime.

proton
gui
web
desktop-app
moon add justjavac/proton@0.1.14
Download zip
Author
Version
0.1.14
License
Apache-2.0
Last updated
13 days ago
Downloads
177
README

#justjavac/proton

MoonBit facade for building Proton desktop applications on the native runtime. This package is the public app surface: windows, entries, commands, events, and lifecycle hooks are all configured from MoonBit code. For the full development workflow — scaffolding, CEF runtime setup, dev mode, and packaging — see the repository README and the proton_cli tool.

#Quick example

fn main {
@proton.run(() => {
@proton.html("Hello", "<h1>Hello</h1>").run_or_abort()
})
}

@proton.run starts the managed application runner from a synchronous main; the closure builds the app and runs it. @proton.html accepts optional width?, height?, debug?, and resizable? arguments.

#Entry points

  • @proton.html(title, html, ...) — inline HTML document.
  • @proton.url(title, url, ...) — a remote or local URL.
  • @proton.file(title, path, ...) — an HTML file on disk.
  • @proton.asset(title, path, ...) — an HTML asset shipped with the app.
  • @proton.config("moon.proton") — an app described by a moon.proton file.
  • @proton.app() — config from PROTON_CONFIG_PATH, moon.proton in the current working directory, or code-only defaults.

#Commands and events

Register typed commands on the app builder:

@proton.config("moon.proton")
.commands(fn(registrar) raise { registrar.bind(ping_command, ping) })
.run_or_abort()

@proton.CommandRegistrar binds contract command descriptors to async handlers; each handler receives a @proton.CommandContext and the decoded request payload. The backend emits events to the renderer with CommandContext::emit(event, payload). JavaScript invokes commands and subscribes to events through the bridge installed on window: commands are called by their contract operation name through core.invokeOp, and backend events arrive on the events channel. For a contract with namespace app:

const reply = await window.__MoonBit__.core.invokeOp("ext:app/ping", { name: "proton", }); window.__MoonBit__.events.on("app.tick", (event) => console.log(event.payload));

Extensions built on justjavac/proton_ext additionally install namespaced proxies such as window.__MoonBit__.ticker.start(...).

#Windows

Add secondary windows to the app builder:

@proton.html("Main", main_html)
.add_window(
"settings",
"Settings",
@proton.AppEntry::Html(settings_html),
width=420,
height=320,
)

The window id "main" is reserved for the primary window. The process exits when all windows have closed.

#Headless mode

.headless() runs the app off-screen without creating a native window. Set PROTON_HEADLESS=1 to force headless mode for automated test runs.

#Learn more

  • Runnable demos live in the repository's examples/ directory.
  • The CLI covers the project workflow: proton_cli new, proton_cli cef setup, proton_cli dev, proton_cli build, and proton_cli package.

#
AppEntry

Declarative entry content loaded into a Proton application window.

#
BridgeDiagnostic

#
BridgeLifecycleState

#
CommandContext

using @justjavac/proton/core { type AppCommandRequestContext as CommandContext }

Request-scoped context supplied to typed application command handlers.

Lifecycle-owned task and event capabilities are added by the application runner; the registrar keeps handlers independent from transport details.

#
CommandRegistrar

Startup-only capability for binding typed command descriptors to handlers.

A top-level native menu and its items.

An application-level native menu bar.

A command, separator, or platform role in a native menu.

#
NativeError

Failures at the MoonBit/native runtime boundary.

#
PermissionGrant

Grants one extension to one trusted source in one application window.

Extension registration and permission grants are deliberately separate: registering an extension makes its backend implementation available, while a grant decides which renderer may invoke it. scope is interpreted by the extension and is always copied at the manifest boundary.

#
PermissionOrigin

Selects the trusted page source covered by a permission grant.

#
PermissionScopeValidationError

A stable validation failure for an extension's renderer permission scope.

#
ProcessResult

#
RuntimeConfig

#
RuntimeEvent

#
RuntimeInfo

#
RuntimeLaunchInput

A macOS application activation delivered by Launch Services or the Dock.

#
TitlebarStyle

#
WindowConfig

#
WindowMonitor

Geometry and scaling information for the monitor containing a window.

#
WindowSizeHint

Controls how the configured width and height constrain native resizing.

#
WindowState

A point-in-time native window state snapshot.

#
AppCleanupError

A failure from one stage of best-effort application teardown.

#
AppCleanupError::message

fn AppCleanupError::message(self : AppCleanupError) -> String

#
AppConfigurationError

pub(all) suberror AppConfigurationError {
InvalidSetting(name~ : String, message~ : String)
Bootstrap(
BootstrapError
)
ExtensionDependencyCycle(extension_id~ : String)
ExtensionUnavailable(extension_id~ : String, requested_by~ : String?, state~ : String)
ExtensionAdaptationFailed(extension_id~ : String, error~ :
ExtensionAdapterError
)
InvalidJavaScriptNamespace(js_namespace~ : String)
InvalidJavaScriptApi(js_namespace~ : String, api_name~ : String)
InvalidEntryUrl(url~ : String, reason~ : String)
InvalidPermissionGrant(detail~ : String)
MissingPermissionGrant(extension_id~ : String)
} derive(
Debug
)

Failures while resolving and validating an application's configuration.

#
AppConfigurationError::message

fn AppConfigurationError::message(self : AppConfigurationError) -> String

#
AppEntryError

pub(all) suberror AppEntryError {
ReadFailed(path~ : String, detail~ : String)
NativeLoad(action~ : String, error~ :
NativeError
)
ClosedDuringStartup
} derive(
Debug
)

Failures while loading the application's initial document.

#
AppEntryError::message

fn AppEntryError::message(self : AppEntryError) -> String

#
AppPathError

pub(all) suberror AppPathError {
InvalidIdentifier(identifier~ : String)
MissingHomeDirectory(platform~ : String)
PlatformProbe(
NativeError
)
} derive(Eq,
Debug
)

Failures while resolving framework-owned application paths.

#
AppPathError::message

fn AppPathError::message(self : AppPathError) -> String

#
AppRunError

pub(all) suberror AppRunError {
RunnerError(String)
ConfigurationError(AppConfigurationError)
UnsupportedNativeFeature(feature~ : String)
NativeRuntimeError(action~ : String, error~ :
NativeError
)
RuntimeWakeupError(RuntimeWakeupError)
CommandExtensionLifecycleError(CommandExtensionLifecycleError)
LifecycleHookError(LifecycleHookError)
EntryLoadError(AppEntryError)
BridgeStartupError(
BridgeDiagnostic
)
BridgeRuntimeError(
BridgeDiagnostic
)
CleanupFailed(primary~ : String?, failures~ : Array[AppCleanupError])
UnexpectedTaskFailure(detail~ : String)
} derive(
Debug
)

Failures produced while configuring, starting, or running an application.

#
AppRunError::message

fn AppRunError::message(self : AppRunError) -> String

#
CommandExtensionLifecycleError

pub(all) suberror CommandExtensionLifecycleError {
ApplicationRegistrationFailed(detail~ : String)
RegistrationFailed(extension_id~ : String, detail~ : String)
DestroyFailed(extension_id~ : String, detail~ : String)
} derive(
Debug
)

Failures while starting or stopping command extensions.

#
CommandExtensionLifecycleError::message

#
LifecycleHookError

pub(all) suberror LifecycleHookError {
ApplicationStart(index~ : Int, detail~ : String)
ApplicationShutdown(index~ : Int, detail~ : String)
WindowReady(index~ : Int, detail~ : String)
WindowClose(index~ : Int, detail~ : String)
} derive(
Debug
)

Failures produced by application or window lifecycle hooks.

#
LifecycleHookError::message

fn LifecycleHookError::message(self : LifecycleHookError) -> String

#
NotificationDeliveryError

pub(all) suberror NotificationDeliveryError {
Native(
NativeError
)
WaitInterrupted(detail~ : String)
} derive(Eq,
Debug
)

Failures while starting or waiting for native notification delivery.

#
NotificationDeliveryError::message

#
RuntimeWakeupError

pub(all) suberror RuntimeWakeupError {
UnsupportedFeature(feature~ : String)
PipeCreateFailed(detail~ : String)
SourceOpenFailed(source~ : String, detail~ : String)
SourceClosed
MissingNotification
} derive(
Debug
)

Failures in the MoonBit-side runtime wakeup source.

#
RuntimeWakeupError::message

fn RuntimeWakeupError::message(self : RuntimeWakeupError) -> String

#
WindowSessionError

pub(all) suberror WindowSessionError {
UnknownWindow(id~ : String)
AlreadyOpen(id~ : String)
StaleWindow(id~ : String)
Cancelled
OperationFailed(action~ : String, error~ :
NativeError
)
StartupFailed(id~ : String, error~ : AppRunError)
} derive(
Debug
)

Failures from runtime window lookup, creation, or control.

#
WindowSessionError::message

fn WindowSessionError::message(self : WindowSessionError) -> String

#
App

type App

High-level application facade for ordinary Proton apps.

#
App::add_window

fn App::add_window(self : App, id : String, title : String, entry :
AppEntry
, width? : Int, height? : Int, size_hint? :
WindowSizeHint
, titlebar_style? :
TitlebarStyle
, open_on_start? : Bool) -> App

Adds a secondary window owned by the standard application lifecycle.

#
App::app_lifecycle

fn[State] App::app_lifecycle(self : App, on_start~ : async (ApplicationContext) -> State, on_shutdown~ : async (State) -> Unit) -> App

Adds a paired application lifecycle hook.

The startup state is passed to shutdown. Completed hooks shut down in reverse order, including when a later startup hook fails.

#
App::bridge_startup_timeout_ms

fn App::bridge_startup_timeout_ms(self : App, timeout_ms : Int) -> App

Sets the maximum time allowed for the native bridge to become ready.

#
App::commands

fn App::commands(self : App, register : (
CommandRegistrar
) -> Unit raise) -> App

Adds one package registrar for typed application commands.

Registration runs before any window is created and is sealed before the renderer bridge starts accepting requests.

#
App::debug

fn App::debug(self : App, enabled? : Bool) -> App

Enables or disables runtime debug mode.

#
App::debug_level

fn App::debug_level(self : App, debug : Int) -> App

Sets the runtime debug level.

#
App::entry_asset

fn App::entry_asset(self : App, path : String) -> App

Overrides the primary app entry with an asset path.

#
App::entry_file

fn App::entry_file(self : App, path : String) -> App

Overrides the primary app entry with a file path.

#
App::entry_html

fn App::entry_html(self : App, html : String) -> App

Overrides the primary app entry with inline HTML.

#
App::entry_url

fn App::entry_url(self : App, url : String) -> App

Overrides the primary app entry with a URL.

#
App::expose

fn App::expose(self : App, extension :
Extension
, window? : String, origin? :
PermissionOrigin
, scope? : Json) -> App

Registers an extension and explicitly exposes it to one trusted page.

Use extension plus permission separately when an extension provides a typed permission builder, such as the filesystem extension.

#
App::extension

fn App::extension(self : App, extension :
Extension
) -> App

Registers one extension setting with the app facade.

The native DLL route exposes command extensions through window.__MoonBit__.core.invokeOp(...) and generated high-level proxies. The renderer installs the bridge before the page's first script executes.

#
App::extensions

fn App::extensions(self : App, extensions :
Extensions
) -> App

Registers a set of extension settings with the app facade.

#
App::headless

fn App::headless(self : App, enabled? : Bool) -> App

Enables or disables off-screen headless rendering for the application.

Headless mode does not create a native top-level window. Set PROTON_HEADLESS=1 to force this mode for automated test runs.

#
App::menu

Sets the app-level native menu bar.

#
App::on_certificate_error

fn App::on_certificate_error(self : App, handler : async (BrowserHandle, CertificateError) -> BrowserPermissionDecision noraise) -> App

Reviews invalid TLS certificates. The default is denial.

#
App::on_download_event

fn App::on_download_event(self : App, handler : async (BrowserHandle, DownloadEvent) -> Unit noraise) -> App

Observes download progress and terminal states.

#
App::on_download_request

fn App::on_download_request(self : App, handler : async (BrowserHandle, DownloadRequest) -> DownloadDecision noraise) -> App

Reviews downloads before CEF chooses a destination.

#
App::on_launch_input

fn App::on_launch_input(self : App, handler : async (
RuntimeLaunchInput
) -> Unit noraise) -> App

Registers an application-level handler for URL, file, and reopen inputs.

#
App::on_media_permission_request

fn App::on_media_permission_request(self : App, handler : async (BrowserHandle, MediaPermissionRequest) -> BrowserPermissionDecision noraise) -> App

Reviews camera, microphone, and display-capture requests. The default is denial.

#
App::on_navigation_request

fn App::on_navigation_request(self : App, handler : async (BrowserHandle, NavigationRequest) -> NavigationDecision noraise) -> App

Reviews top-level navigations asynchronously. The native browser cancels a pending navigation until this handler returns, then replays it exactly once when allowed.

#
App::on_popup_request

fn App::on_popup_request(self : App, handler : async (BrowserHandle, PopupRequest) -> PopupDecision noraise) -> App

Reviews window.open and new-tab requests. New Proton windows must already be declared with add_window(..., open_on_start=false).

#
App::on_window_close_request

fn App::on_window_close_request(self : App, handler : async (WindowHandle) -> WindowCloseDecision noraise) -> App

Intercepts user-initiated close requests without blocking the native UI thread. WindowHandle::close uses the same request path; forced cleanup is reserved for the session-owned destroy lifecycle.

#
App::on_window_event

fn App::on_window_event(self : App, handler : async (WindowHandle, WindowEvent) -> Unit noraise) -> App

Observes coalesced native state changes for every running window.

#
App::permission

Grants one registered extension to a trusted source in one window.

Extension registration alone never exposes renderer capabilities.

#
App::run

async fn App::run(self : App) -> Unit raise AppRunError

Runs the configured app through the native Proton runtime.

#
App::run_or_abort

async fn App::run_or_abort(self : App) -> Unit

Runs the configured app and aborts with the error message on failure.

#
App::single_instance

fn App::single_instance(self : App, identifier : String) -> App

Ensures only one operating-system process owns this application identity. Later processes forward their URL, document, or reopen activation and exit.

#
App::size

fn App::size(self : App, width~ : Int, height~ : Int) -> App

Sets the primary window size.

#
App::title

fn App::title(self : App, title : String) -> App

Sets the primary window title.

#
App::titlebar_style

fn App::titlebar_style(self : App, style :
TitlebarStyle
) -> App

Sets whether web content remains below or extends beneath the native titlebar. Overlay rendering is currently implemented on macOS and Windows.

#
App::window_lifecycle

fn[State] App::window_lifecycle(self : App, on_ready~ : async (WindowContext) -> State, on_close~ : async (State) -> Unit) -> App

Adds a paired primary-window lifecycle hook.

The ready state is passed to close. Completed hooks close in reverse order, including when a later ready hook fails.

#
ApplicationContext

pub struct ApplicationContext {
tasks :
TaskGroup
[Unit]
windows : WindowManager
}

Application-lifetime capabilities supplied to startup hooks.

#
ApplicationContext::task_group

Returns the structured task group owned by this application.

#
ApplicationContext::windows

Returns the window manager owned by this running application.

#
BrowserHandle

pub struct BrowserHandle {
id : String
native_id : Int64
load_browser_url : (String) -> Unit raise WindowSessionError
load_browser_html : (String, String) -> Unit raise WindowSessionError
eval_browser_script : (String) -> Unit raise WindowSessionError
send_browser_command : (String, Int?) -> Unit raise WindowSessionError
}

#
BrowserHandle::back

fn BrowserHandle::back(self : BrowserHandle) -> Unit raise WindowSessionError

#
BrowserHandle::cancel_download

fn BrowserHandle::cancel_download(self : BrowserHandle, download_id : Int) -> Unit raise WindowSessionError

#
BrowserHandle::close_devtools

fn BrowserHandle::close_devtools(self : BrowserHandle) -> Unit raise WindowSessionError

#
BrowserHandle::eval

fn BrowserHandle::eval(self : BrowserHandle, script : String) -> Unit raise WindowSessionError

#
BrowserHandle::forward

fn BrowserHandle::forward(self : BrowserHandle) -> Unit raise WindowSessionError

#
BrowserHandle::load_html

fn BrowserHandle::load_html(self : BrowserHandle, html : String, base_url : String) -> Unit raise WindowSessionError

#
BrowserHandle::load_url

fn BrowserHandle::load_url(self : BrowserHandle, url : String) -> Unit raise WindowSessionError

#
BrowserHandle::open_devtools

fn BrowserHandle::open_devtools(self : BrowserHandle) -> Unit raise WindowSessionError

#
BrowserHandle::reload

fn BrowserHandle::reload(self : BrowserHandle, ignore_cache? : Bool) -> Unit raise WindowSessionError

#
BrowserHandle::stop

fn BrowserHandle::stop(self : BrowserHandle) -> Unit raise WindowSessionError

#
BrowserHandle::window_id

fn BrowserHandle::window_id(self : BrowserHandle) -> String

#
BrowserPermissionDecision

pub(all) enum BrowserPermissionDecision {
Allow
Deny
} derive(Eq,
Debug
)

#
CertificateError

pub(all) struct CertificateError {
url : String
error_code : Int
} derive(Eq,
Debug
)

#
DownloadDecision

pub(all) enum DownloadDecision {
Deny
ShowSaveDialog
SaveTo(String)
} derive(Eq,
Debug
)

#
DownloadEvent

pub(all) struct DownloadEvent {
id : Int
state : String
received_bytes : Int64
total_bytes : Int64
percent : Int
} derive(Eq,
Debug
)

#
DownloadRequest

pub(all) struct DownloadRequest {
id : Int
url : String
suggested_name : String
} derive(Eq,
Debug
)

#
MediaPermissionRequest

pub(all) struct MediaPermissionRequest {
origin : String
permissions : Int
} derive(Eq,
Debug
)

pub(all) enum NavigationDecision {
Allow
Deny
} derive(Eq,
Debug
)

pub(all) struct NavigationRequest {
url : String
http_method : String
user_gesture : Bool
redirect : Bool
} derive(Eq,
Debug
)

#
PopupDecision

pub(all) enum PopupDecision {
Deny
OpenInCurrent
OpenInWindow(String)
} derive(Eq,
Debug
)

#
PopupRequest

pub(all) struct PopupRequest {
url : String
disposition : Int
user_gesture : Bool
} derive(Eq,
Debug
)

#
WindowCloseDecision

pub(all) enum WindowCloseDecision {
Allow
Deny
} derive(Eq,
Debug
)

The result of an asynchronous native close request.

#
WindowContext

pub struct WindowContext {
id : String
window :
WindowRef

handle : WindowHandle
windows : WindowManager
tasks :
TaskGroup
[Unit]
events : WindowEventEmitter
}

Window-lifetime capabilities supplied to window startup hooks.

#
WindowContext::events

Returns an event emitter bound to this window's active page.

#
WindowContext::handle

Returns the session-controlled handle for this concrete window instance.

#
WindowContext::id

fn WindowContext::id(self : WindowContext) -> String

Returns the declarative id of this window. The primary window uses "main".

#
WindowContext::task_group

Returns the structured task group owned by this window.

#
WindowContext::window

Returns a non-owning reference to this window.

#
WindowContext::windows

Returns the application window manager.

#
WindowEvent

An observed change to a running native window.

#
WindowEventEmitter

pub struct WindowEventEmitter {
emit_event : async (
ContractRoute
, String, Json) -> Unit noraise
}

A typed event destination bound to one explicit window.

#
WindowEventEmitter::emit

async fn[Payload : ToJson] WindowEventEmitter::emit(self : WindowEventEmitter, event :
Event
[Payload], payload : Payload) -> Unit

Emits a typed event to this emitter's window.

#
WindowHandle

pub struct WindowHandle {
id : String
native_id : Int64
show_window : () -> Unit raise WindowSessionError
hide_window : () -> Unit raise WindowSessionError
close_window : () -> Unit raise WindowSessionError
focus_window : () -> Unit raise WindowSessionError
set_window_title : (String) -> Unit raise WindowSessionError
set_window_size : (Int, Int) -> Unit raise WindowSessionError
minimize_window : () -> Unit raise WindowSessionError
maximize_window : () -> Unit raise WindowSessionError
restore_window : () -> Unit raise WindowSessionError
set_window_fullscreen : (Bool) -> Unit raise WindowSessionError
set_window_position : (Int, Int) -> Unit raise WindowSessionError
set_window_always_on_top : (Bool) -> Unit raise WindowSessionError
set_window_zoom_percent : (Int) -> Unit raise WindowSessionError
read_window_state : () ->
WindowState
raise WindowSessionError
browser : BrowserHandle
}

A non-owning reference to one concrete window instance.

The instance id prevents a stale handle from targeting a later window that reuses the same declarative id.

#
WindowHandle::as_native_ref

Returns a low-level non-owning reference for APIs such as dialogs.

#
WindowHandle::browser

fn WindowHandle::browser(self : WindowHandle) -> BrowserHandle

#
WindowHandle::close

fn WindowHandle::close(self : WindowHandle) -> Unit raise WindowSessionError

#
WindowHandle::focus

fn WindowHandle::focus(self : WindowHandle) -> Unit raise WindowSessionError

#
WindowHandle::hide

fn WindowHandle::hide(self : WindowHandle) -> Unit raise WindowSessionError

#
WindowHandle::id

fn WindowHandle::id(self : WindowHandle) -> String

Returns the declarative id of this window.

#
WindowHandle::maximize

fn WindowHandle::maximize(self : WindowHandle) -> Unit raise WindowSessionError

#
WindowHandle::minimize

fn WindowHandle::minimize(self : WindowHandle) -> Unit raise WindowSessionError

#
WindowHandle::restore

fn WindowHandle::restore(self : WindowHandle) -> Unit raise WindowSessionError

#
WindowHandle::set_always_on_top

fn WindowHandle::set_always_on_top(self : WindowHandle, always_on_top : Bool) -> Unit raise WindowSessionError

#
WindowHandle::set_fullscreen

fn WindowHandle::set_fullscreen(self : WindowHandle, fullscreen : Bool) -> Unit raise WindowSessionError

#
WindowHandle::set_position

fn WindowHandle::set_position(self : WindowHandle, x : Int, y : Int) -> Unit raise WindowSessionError

#
WindowHandle::set_size

fn WindowHandle::set_size(self : WindowHandle, width : Int, height : Int) -> Unit raise WindowSessionError

#
WindowHandle::set_title

fn WindowHandle::set_title(self : WindowHandle, title : String) -> Unit raise WindowSessionError

#
WindowHandle::set_zoom_percent

fn WindowHandle::set_zoom_percent(self : WindowHandle, zoom_percent : Int) -> Unit raise WindowSessionError

#
WindowHandle::show

fn WindowHandle::show(self : WindowHandle) -> Unit raise WindowSessionError

#
WindowManager

pub struct WindowManager {
open_window : async (String) -> WindowHandle raise WindowSessionError
find_window : (String) -> WindowHandle?
}

Opens and locates windows declared by the application manifest.

#
WindowManager::find

fn WindowManager::find(self : WindowManager, id : String) -> WindowHandle?

Returns the active instance for a declared window id.

#
WindowManager::open

async fn WindowManager::open(self : WindowManager, id : String) -> WindowHandle raise WindowSessionError

Opens one declared window that is not currently active.

#
abi_version

fn abi_version() -> Int

#
app

fn app() -> App

Creates an application from PROTON_CONFIG_PATH, moon.proton in the current working directory, or code-only defaults.

#
app_data_dir

fn app_data_dir(identifier : String) -> String raise AppPathError

Resolves the stable per-application directory for native persistent data.

The identifier should match the packaged bundle/application identifier. This function resolves the path but does not create the directory.

#
asset

fn asset(title : String, path : String, width? : Int, height? : Int, debug? : Bool, resizable? : Bool) -> App

Creates an inline asset application.

#
config

fn config(path : String) -> App

Creates an application backed by a moon.proton config file.

The default moon.proton path honors PROTON_CONFIG_PATH and packaged config discovery. Other paths are used exactly as provided.

#
file

fn file(title : String, path : String, width? : Int, height? : Int, debug? : Bool, resizable? : Bool) -> App

Creates an inline file application.

#
html

fn html(title : String, html : String, width? : Int, height? : Int, debug? : Bool, resizable? : Bool) -> App

Creates an inline HTML application.

#
last_error_message

fn last_error_message() -> String

#
run

fn run(main : async () -> Unit) -> Unit

Runs a Proton application with the platform UI loop on the process main thread and MoonBit async work on Proton's application thread.

Call this once from a synchronous main.

#
runtime_info_json

fn runtime_info_json() -> String raise
NativeError

#
url

fn url(title : String, url : String, width? : Int, height? : Int, debug? : Bool, resizable? : Bool) -> App

Creates an inline URL application.