Skip to content

aivi.portal ​

Types for working with desktop portals.

Portals are the standard Linux desktop way to ask the system for privileged actions such as opening a file chooser, opening a URI, or taking a screenshot. They are especially useful for sandboxed apps.

This module exports the result and error types used by the built-in desktop portal sources.

Portal work stays under provider-backed @source variants rather than a separate task-first portal handle family.

Import ​

aivi
use aivi.portal (
    PortalError
    PortalFileFilter
    PortalFileSelection
    PortalUriResult
    PortalScreenshotResult
    PortalTask
)

Overview ​

ItemTypeDescription
PortalErrortypeThings that can go wrong while talking to a portal
PortalFileFilterrecordOne file chooser filter
PortalFileSelectiontypeResult of choosing files
PortalUriResulttypeResult of asking the desktop to open a URI
PortalScreenshotResulttypeResult of requesting a screenshot
PortalTask ATask PortalError AGeneric portal task alias
portal.openFileSignal (Result PortalError PortalFileSelection)Built-in file chooser source
portal.openUriSignal (Result PortalError PortalUriResult)Built-in URI-opening source
portal.screenshotSignal (Result PortalError PortalScreenshotResult)Built-in screenshot source

Types ​

PortalError ​

aivi
type PortalError =
  | PortalUnavailable
  | UserCancelled
  | PortalPermissionDenied Text
  | PortalDecodeFailed Text

These variants describe why a portal request could not complete.

  • PortalUnavailable — no usable portal backend is available
  • UserCancelled — the request was cancelled before a usable result was produced
  • PortalPermissionDenied — the desktop rejected the request
  • PortalDecodeFailed — the portal replied, but the data could not be decoded cleanly

PortalFileFilter ​

aivi
type PortalFileFilter = {
    name: Text,
    patterns: List Text
}

One filter option for a file chooser.

  • name — label shown to the user
  • patterns — filename patterns such as "*.aivi" or "*.png"
aivi
use aivi.portal (PortalFileFilter)

value aiviFiles : PortalFileFilter = {
    name: "AIVI Files",
    patterns: ["*.aivi"]
}

PortalFileSelection ​

aivi
type PortalFileSelection =
  | SingleFile Text
  | MultipleFiles (List Text)
  | SelectionCancelled

Result of a file chooser operation.

  • SingleFile — one selected path or URI
  • MultipleFiles — several selected paths or URIs
  • SelectionCancelled — chooser closed without a selection
aivi
use aivi.portal (
    PortalFileSelection
    SingleFile
    MultipleFiles
    SelectionCancelled
)

type PortalFileSelection -> Text
func selectionSummary =
 ||> SingleFile path     -> path
 ||> MultipleFiles paths -> "Several files selected"
 ||> SelectionCancelled  -> "No file selected"

PortalUriResult ​

aivi
type PortalUriResult =
  | UriOpened Text
  | UriOpenCancelled
  | UriOpenFailed Text

Result of asking the desktop to open a URI.

  • UriOpened — the request was accepted for the given URI
  • UriOpenCancelled — the user or system cancelled the request
  • UriOpenFailed — the request failed with a message

PortalScreenshotResult ​

aivi
type PortalScreenshotResult =
  | ScreenshotBytes Bytes
  | ScreenshotCancelled

Result of a screenshot request.

  • ScreenshotBytes — screenshot bytes were returned
  • ScreenshotCancelled — the request was cancelled

PortalTask ​

aivi
use aivi.portal (PortalError)

type PortalTask A = (Task PortalError A)

Generic alias for portal-related tasks.

Built-in source shapes ​

These source variants are implemented today:

aivi
use aivi.portal (
    PortalError
    PortalFileSelection
    PortalScreenshotResult
    PortalUriResult
)

@source portal.openFile { title: "Open attachment", multiple: True }
signal openedFile : Signal (Result PortalError PortalFileSelection)

@source portal.openUri "https://example.com" with {
    ask: True
}
signal uriResult : Signal (Result PortalError PortalUriResult)

@source portal.screenshot with {
    interactive: True
}
signal screenshot : Signal (Result PortalError PortalScreenshotResult)

portal.openFile ​

Form: @source portal.openFile config

config is currently a record with these supported fields:

FieldTypeMeaning
titleTextDialog title. Default: "Open File"
acceptLabelTextCustom accept button label
modalBoolModal hint. Default: True
multipleBoolAllow multiple selection
directoryBoolPick folders instead of files
currentFolderTextSuggested starting folder path
filtersList PortalFileFilterGlob-based chooser filters

portal.openFile returns:

  • Ok (SingleFile uri) for one selected file
  • Ok (MultipleFiles uris) for multi-select
  • Ok SelectionCancelled if chooser is cancelled
  • Err PortalUnavailable | PortalPermissionDenied | PortalDecodeFailed for runtime/protocol failures

portal.openUri ​

Form: @source portal.openUri uri

Supported options:

OptionTypeMeaning
askBoolAsk desktop to prompt for app choice
writableBoolRequest writable handoff where supported
activationTokenTextForward activation token to launched app
refreshOnSignal AStandard request retrigger
activeWhenSignal BoolStandard lifecycle gate

portal.openUri returns Ok (UriOpened uri), Ok UriOpenCancelled, or Ok (UriOpenFailed message).

portal.screenshot ​

Form: @source portal.screenshot

Supported options:

OptionTypeMeaning
interactiveBoolAsk portal backend for interactive capture UI
modalBoolModal hint
refreshOnSignal AStandard request retrigger
activeWhenSignal BoolStandard lifecycle gate

portal.screenshot reads the portal-provided file URI and returns Ok (ScreenshotBytes bytes) or Ok ScreenshotCancelled.

Task alias ​

PortalTask A is Task PortalError A.

(c) 2026 by Andreas Herd