Native packaging and @nexa/platform
The same source code compiles to a real desktop binary (Tauri), a real APK (Capacitor Android), or a real Xcode project (Capacitor iOS) — without rewriting anything. Web, desktop, Android and iOS from a single project, and @nexa/platform is what makes the same handler work across all three with no branches of your own.
Desktop with Tauri
nexa add tauri
cd src-tauri && cargo build
# a real, runnable desktop binaryGenerates a real src-tauri/ — cargo build produces a real, runnable desktop binary on Windows, macOS and Linux.
Android with Capacitor
nexa add capacitor
npx @capacitor/cli add android
cd android && ./gradlew assembleDebug
# real APK at app/build/outputs/apk/debug/Requires the Android SDK installed — the result is a real APK, built with Gradle. Verified end to end with a real SDK.
iOS with Capacitor
nexa add capacitor
npx @capacitor/cli add ios
npx cap open ios
# opens the real project in Xcode (requires macOS)Same capacitor.config.json as Android — add ios generates a real Xcode project (ios/). Needs macOS with Xcode to build: not tested in this Linux environment, but the mechanism is identical to Android's.
@nexa/platform: one handler, three platforms
function shareThis() {
platform.share({ title: "Nexa", url: location.href });
}
const users = platform.db("users");
await users.set("1", { name: "Ada" });platform.share()/platform.notify()/platform.capturePhoto() call the real Capacitor plugin on Android/iOS (@capacitor/share, etc.) and the standard Web API on web and inside Tauri's webview — without the project writing any branch of its own. platform.storage()/platform.sessionStorage() wrap localStorage/sessionStorage with the same contract across all three environments; platform.cache() gives direct access to the Cache API (no [pwa] declaration needed); platform.db("name") is a minimal wrapper over IndexedDB, with nothing to declare upfront. Every function throws a clear Error if the capability isn't available — never fails silently.
Dark theme, network and lifecycle
platform.theme.set("dark");
platform.network.onChange((status) => {
console.log(status.online, status.type);
});
platform.lifecycle.onChange((state) => {
console.log(state.active ? "active" : "backgrounded");
});platform.theme.set("dark"|"light"|"system") persists the preference and lets it win over the system's prefers-color-scheme (never calling it, the site already respects that). platform.network.getStatus()/onChange() give the real connectivity state (online/offline, plus the connection type on Capacitor); platform.lifecycle.getState()/onChange() report when the app goes to the background or comes back — via @capacitor/app on Capacitor, via document.hidden/visibilitychange on web. It grows one module at a time, based on real need: geolocation, deep links, real push, biometrics and haptics aren't there yet.