@nexa/platform
A platform object always available, with a single codebase for Web/Tauri/Capacitor.
platform.notify()
await platform.notify({ title, body })A real OS-level notification. Web: Notification API (asks for permission). Capacitor: @capacitor/local-notifications.
platform.capturePhoto()
const { dataUrl } = await platform.capturePhoto();Web: getUserMedia + canvas. Capacitor: @capacitor/camera. Returns { dataUrl }.
platform.storage() / sessionStorage()
const storage = platform.storage();
storage.set("theme", "dark");
storage.get("theme");
const session = platform.sessionStorage(); // mismo contrato, no sobrevive cerrar el navegadorThe same get/set/remove contract over localStorage or sessionStorage — the latter lives only as long as the tab does.
platform.cache()
const cache = await platform.cache("mi-cache");
await cache.put(url, response);
await cache.match(url);Direct Cache API, independent from [pwa.cache] (which lives in the service worker) — for caching something specific from regular code.
platform.db()
const users = platform.db("users");
await users.set(id, valor);
await users.get(id);
await users.list();A minimal wrapper over IndexedDB, not an ORM. Each collection name is its own database — nothing to declare upfront.
platform.network
const status = await platform.network.getStatus(); // { online, type }
const stop = platform.network.onChange((status) => { ... });Native Capacitor uses the real @capacitor/network; Web/Tauri use navigator.onLine + the online/offline events. type (wifi/cellular) is Capacitor-only.
platform.lifecycle
const state = await platform.lifecycle.getState(); // { active }
const stop = platform.lifecycle.onChange((state) => { ... });Native Capacitor uses @capacitor/app (getState/appStateChange); Web/Tauri use document.hidden + visibilitychange — the same signal @capacitor/app's own web branch uses.
platform.geolocation
const position = await platform.geolocation.getCurrentPosition();
const stop = platform.geolocation.watchPosition((position) => { ... });Native Capacitor uses @capacitor/geolocation; Web/Tauri use navigator.geolocation — the same API @capacitor/geolocation's own web branch uses internally.
platform.deepLinks
const launch = await platform.deepLinks.getLaunchUrl(); // { url: "" } en Web
const stop = platform.deepLinks.onOpen((event) => { ... });Native Capacitor uses @capacitor/app (getLaunchUrl/appUrlOpen). Web/Tauri: getLaunchUrl() always returns an empty url and onOpen() never fires — that's exactly how @capacitor/app's own web branch behaves.
platform.push
const registration = await platform.push.register({ vapidPublicKey });
// { platform: "capacitor", token } | { platform: "web", subscription }
platform.push.onReceived((n) => { ... }); // solo CapacitorDeliberately smaller than the full Capacitor plugin: registration + receiving only. register() returns a discriminated union because Capacitor and Web don't share a registration shape.
platform.biometrics
const status = await platform.biometrics.isAvailable(); // { isAvailable, biometryType }
await platform.biometrics.authenticate({ reason: "Desbloquear" });Native Capacitor uses @aparajita/capacitor-biometric-auth. Web/Tauri use real WebAuthn — that plugin's own web branch wasn't replicated because it's a deliberate simulation, not real biometrics.
platform.haptics
await platform.haptics.impact({ style: "MEDIUM" });
await platform.haptics.notification({ type: "ERROR" });
await platform.haptics.vibrate({ duration: 250 });Native Capacitor uses the real @capacitor/haptics. Web/Tauri use navigator.vibrate — the same API @capacitor/haptics' own web branch uses.