DropletHost

Everything the host offers a droplet.

@MainActor struct DropletHost

A droplet receives one of these in activate(host:) and should store it. There is no global accessor and no singleton: if you did not keep the host, you cannot reach the host, which is deliberate. It keeps a droplet's dependencies visible in its own source and lets the harness hand you a different implementation without changing a line of droplet code.

Capabilities

Services are present whether or not the droplet is allowed to use them, but the effect is gated: a call the droplet lacks the capability for returns false, nil, or does nothing, and the host logs the refusal. Check isGranted(_:) when you want to hide UI for something you cannot do, rather than offering a button that will quietly fail.

Declare the capabilities you need in droplet.json; the store shows them to the user before they install.

final class WorldClockDroplet: Droplet, ShelfWidgetProviding {
    static let id: DropletID = "worldclock"
    private var host: DropletHost?

    func activate(host: DropletHost) throws {
        self.host = host
        let zone = host.preferences.value(forKey: "zone", default: "UTC")
        host.log.info("activated for \(zone)")
    }

    func deactivate() { host = nil }
}

Initializers

init(grantedCapabilities:preferences:environment:log:installState:hud:shelf:liveActivity:notchSurface:shortcuts:workspace:feedback:permissions:)

@MainActor init(grantedCapabilities: Set<DropletPermission>, preferences: any DropletPreferencesService, environment: any DropletEnvironmentService, log: any DropletLogService, installState: any DropletInstallStateService, hud: any DropletHUDService, shelf: any DropletShelfService, liveActivity: any DropletLiveActivityService, notchSurface: any DropletNotchSurfaceService, shortcuts: any DropletShortcutsService, workspace: any DropletWorkspaceService, feedback: any DropletFeedbackService, permissions: any DropletPermissionsService)

Creates a host. Implemented by Droppy and by DroppyKitHarness; droplets never call this.

Properties

environment

@MainActor let environment: any DropletEnvironmentService

Read-only facts about the host and the machine.

feedback

@MainActor let feedback: any DropletFeedbackService

Droppy's own sound and haptic cues.

grantedCapabilities

@MainActor let grantedCapabilities: Set<DropletPermission>

The capabilities the user granted this droplet at install time.

hud

@MainActor let hud: any DropletHUDService

Transient HUDs on the notch surface. Requires hud.

installState

@MainActor let installState: any DropletInstallStateService

Which of this droplet's pieces the user has switched on.

liveActivity

@MainActor let liveActivity: any DropletLiveActivityService

The seat this droplet's live activity currently holds.

log

@MainActor let log: any DropletLogService

Droppy's own log stream, tagged with your droplet id.

notchSurface

@MainActor let notchSurface: any DropletNotchSurfaceService

Expanded (takeover) surfaces. Requires expanded-surface.

permissions

@MainActor let permissions: any DropletPermissionsService

Checking and requesting macOS permissions.

preferences

@MainActor let preferences: any DropletPreferencesService

Persistent, droplet-scoped settings.

shelf

@MainActor let shelf: any DropletShelfService

Opening, closing, and re-measuring the shelf. Requires shelf-read to observe and shelf-write to act.

shortcuts

@MainActor let shortcuts: any DropletShortcutsService

Global keyboard shortcuts. Requires global-shortcuts.

workspace

@MainActor let workspace: any DropletWorkspaceService

Opening URLs and files, and writing the pasteboard.

Methods

isGranted(_:)

@MainActor func isGranted(_ capability: DropletPermission) -> Bool

Whether the user granted a capability.

Use it to hide affordances you cannot honour, not as a substitute for handling a refusal: capabilities can be revoked while the droplet runs.