Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

glitor

Type-safe Gleam wrappers for every official Capacitor 8 plugin, plus a Lustre effect adapter — native iOS, Android and Web from one codebase.

CI Licence Capacitor Gleam

18 Gleam packages that wrap Capacitor 8.x end-to-end and smooth the edges for Gleam + Lustre apps:

  • A shared glitor_core with a normalised error ADT, Promise / listener / stream adapters, and the SystemBars API bundled with @capacitor/core.
  • 16 plugin wrappers — one per official Capacitor plugin — built on that core with a uniform Promise(Result(a, GlitorError)) return shape.
  • A glitor_lustre adapter that folds those promises and listener handles into lustre/effect.Effect(msg) values.

Every wrapper is a first-class Gleam package: you depend on only the ones you use, and each comes with its own README.md, CI-tested test suite, and per-plugin setup notes for iOS / Android / Web.

Packages

Package Upstream Tests Highlights
glitor_core @capacitor/core 40 Error ADT, Promise / listener / stream adapters, SystemBars, decoder helpers
glitor_app @capacitor/app 6 7 commands + 6 listeners, Android back-button three-state matrix
glitor_device @capacitor/device 3 OS / platform / battery / per-app language
glitor_network @capacitor/network 2 Connection status + change listener
glitor_preferences @capacitor/preferences 2 Everyday API + legacy migration sub-module
glitor_filesystem @capacitor/filesystem 6 Text / binary API split, read_file_in_chunks streaming, 9-variant Directory
glitor_dialog @capacitor/dialog 2 alert / confirm / prompt (with the cancellation-as-field exception)
glitor_haptics @capacitor/haptics 2 impact / notification / vibrate / selection helpers
glitor_toast @capacitor/toast 2 One-shot toast with short / long duration
glitor_action_sheet @capacitor/action-sheet 7 Button builder, destructive / cancel styles, result decoder
glitor_status_bar @capacitor/status-bar 3 6 commands + 2 listeners, SystemBars role split documented
glitor_splash_screen @capacitor/splash-screen 1 show / hide with launch-config caveats
glitor_keyboard @capacitor/keyboard 3 7 commands + 4 listeners, will / did pairs
glitor_camera @capacitor/camera 14 New 8.1 API + legacy (getPhoto / pickImages) with migration guide
glitor_geolocation @capacitor/geolocation 6 watch_position via glitor/stream, 7-code error mapping
glitor_local_notifications @capacitor/local-notifications 10 Full LocalNotificationSchema, channels, exact-alarm settings
glitor_push_notifications @capacitor/push-notifications 9 FCM / APNS registration flow, channels, Android 13+ permission prompt
glitor_lustre — (Lustre 5.6 adapter) 4 from_promise, register_listener, remove_listener(s), clear_watch
Total 122

Quick start

Pick the plugins your app needs and add them one by one — nothing is bundled.

gleam add glitor_app glitor_network glitor_dialog
gleam add glitor_lustre            # only if you use Lustre

Then install the matching Capacitor peer packages in your application:

npm install @capacitor/core @capacitor/app @capacitor/network @capacitor/dialog
npx cap sync

A minimal example — fetch the app info and log the current network link:

import gleam/javascript/promise
import glitor_app as app
import glitor_network as network

pub fn probe() {
  use info <- promise.try_await(app.get_info())
  use status <- promise.try_await(network.get_status())
  promise.resolve(Ok(#(info.name, status.connected, status.connection_type)))
}

Every glitor_* function returns Promise(Result(a, GlitorError)) — the rejection path is already normalised, so promise.try_await composes them directly. See each package's README.md for per-plugin examples.

Cross-wrapper contract (package_design.md §1)

Every wrapper honours the same behavioural contract so you can move between plugins without re-learning the idioms:

Area Rule
Error shape GlitorError ADT with two-stage mapping: per-wrapper whitelist → project-wide keyword fallback
Option encoding None fields omit the key entirely; the bridge never sees an explicit JS null
Permission state Common 4-variant in glitor/permission; Camera extends with CameraLimited (5 variants)
Listener handles Opaque, equality comparison is meaningless — register in init, not update
Native callback identifiers Opaque CallbackId wrapping upstream type CallbackID = string
Numeric enums Importance, Visibility, MediaType, EncodingType, MediaTypeSelection use glitor/numeric
FFI loader Lazy import("@capacitor/*") — unit tests run without node_modules
package_design.md Always the source of truth for semantics; upstream TypeScript wins on runtime values

Requirements

Toolchain Range
Gleam >= 1.12.0
Capacitor 8.x (@capacitor/core ^8.0.0)
Lustre (adapter) >= 5.0.0 < 6.0.0
Node (Gleam JS target) 22+
iOS 15+, Xcode 26+
Android Studio Otter (2025.2.1)+
App targetSdk 36 is the edge-to-edge boundary (not runtime OS version)

Capacitor 7.x and below are not supported.

Development

# Test any single package
cd glitor_core && gleam test

# Test every package locally (mirror of CI)
for pkg in glitor_*; do (cd $pkg && gleam test) || exit 1; done

Every package has its own gleam.toml. glitor_core is linked into the other wrappers via a path dependency, so a change to the core is picked up by the next gleam test in a dependent package.

Tests do not require any @capacitor/* npm package to be installed — every FFI uses a lazy import(), exercised only when the bridge is actually invoked (not by the encoder / decoder unit tests).

Project layout

glitor/
├── LICENCE
├── README.md                 ← this file
├── glitor_core/              ← shared types + SystemBars
├── glitor_<plugin>/          ← one per official plugin (× 16)
├── glitor_lustre/            ← Lustre effect adapter
├── references/               ← Capacitor v8 docs snapshot + design notes
└── .github/workflows/ci.yml  ← per-package test matrix

Design decisions for the wrapper set live in references/package_design.md; it is the definitive contract that every package conforms to.

Contributing

Before opening a PR, run the full matrix locally:

for pkg in glitor_*; do (cd $pkg && gleam format src test && gleam test) || exit 1; done

When changing glitor_core, always check the downstream wrappers — the path dependency means a core API break surfaces immediately in every wrapper's test suite.

Licence

MIT — see LICENCE. Each package carries an identical copy of the same licence so Hex downloads include it alongside the source.

Acknowledgements

About

Gleam wrappers for every official Capacitor 8 plugin, plus a Lustre effect adapter - native iOS, Android and Web from one codebase.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages