page wrnexusmobile { seo { title = "@wrnexus/mobile" description = "SSR-safe compatibility access to Capacitor plugins." } view {
W WRNexusJS
Browse documentation
Native · Preview

@wrnexus/mobile

SSR-safe compatibility access to Capacitor plugins.

Private registry access required

This package is not available from the public npm registry. After WorkRoot approves access and supplies private registry instructions, install the release-aligned package:

bun add @wrnexus/mobile@0.2.59

Request preview access. Never put registry tokens in source control.

SSR-safe access to Capacitor plugins from WRNexusJS browser code.

Overview

@wrnexus/mobile keeps optional native imports out of server rendering while giving browser-owned modules one consistent registry for Capacitor plugins. During SSR, mobile.isNative() is false and mobile.platform() is "web".

Install a plugin through the WRNexusJS CLI so the web and native projects stay aligned:

wrnexus mobile add @capacitor/camera @capacitor/haptics

Usage

Register and invoke a Capacitor plugin

Import Capacitor packages only from browser-owned code, never from API routes or SSR helpers.

import { Camera, CameraResultType } from "@capacitor/camera";
import { mobile } from "@wrnexus/mobile";

mobile.registerPlugin("Camera", Camera);

export async function takePhoto() {
  if (!mobile.isNative()) return null;
  return mobile.invoke("Camera", "getPhoto", {
    quality: 85,
    resultType: CameraResultType.Uri,
  });
}

Provide a browser fallback

whenNative runs the first callback only in a Capacitor WebView and can return a web/SSR-safe fallback everywhere else.

import { Haptics, ImpactStyle } from "@capacitor/haptics";
import { mobile } from "@wrnexus/mobile";

mobile.registerPlugin("Haptics", Haptics);

export const confirmAction = () =>
  mobile.whenNative(
    () => mobile.invoke("Haptics", "impact", { style: ImpactStyle.Medium }),
    () => navigator.vibrate?.(30),
  );

Read an optional plugin without throwing

import type { NetworkPlugin } from "@capacitor/network";
import { mobile } from "@wrnexus/mobile";

const network = mobile.plugin<NetworkPlugin>("Network");
const status = network ? await network.getStatus() : { connected: true, connectionType: "unknown" };

API

  • registerPlugin(name, instance) registers a browser-imported plugin.
  • plugin(name) returns a plugin or undefined; requirePlugin(name) throws when absent.
  • invoke(plugin, method, options?) calls a registered method and returns its result.
  • whenNative(native, fallback?) selects native behavior without breaking SSR.
  • isNative() and platform() report the current Capacitor environment.

Unavailable required plugins throw MobileUnavailableError with an actionable message.

Requirements / Notes

  • Capacitor plugin imports must remain in browser-owned modules.
  • @wrnexus/mobile re-exports native from @wrnexus/native for applications that
  • prefer the higher-level cross-platform capability API.

Complete TypeScript API

This declaration comes from the exact installed package and lists its exported functions, classes, interfaces, and types.

export { native } from '@wrnexus/native';

/** @wrnexus/mobile — SSR-safe access to Capacitor's native bridge. */

type MobilePlatform = "ios" | "android" | "web" | string;
interface CapacitorBridge {
    isNativePlatform?: () => boolean;
    getPlatform?: () => MobilePlatform;
    Plugins?: Record<string, unknown>;
}
declare class MobileUnavailableError extends Error {
    constructor(message?: string);
}
/** Register a plugin imported by browser-only application code. */
declare function registerPlugin<T extends object>(name: string, instance: T): T;
/** True only inside a native Capacitor iOS or Android WebView. SSR-safe. */
declare function isNative(): boolean;
/** Current Capacitor platform, falling back to `web` during SSR and in browsers. */
declare function platform(): MobilePlatform;
/** Return an injected Capacitor plugin, or undefined when it is unavailable. */
declare function plugin<T extends object>(name: string): T | undefined;
/** Require an installed native plugin and produce a useful error when absent. */
declare function requirePlugin<T extends object>(name: string): T;
/** Invoke a plugin method without importing native code into an SSR module. */
declare function invoke<TResult = unknown>(pluginName: string, method: string, options?: unknown): Promise<TResult>;
/** Run native behavior when available, with an optional SSR/web fallback. */
declare function whenNative<T>(native: () => T | Promise<T>, fallback?: () => T | Promise<T>): Promise<T | undefined>;
declare const mobile: {
    isNative: typeof isNative;
    platform: typeof platform;
    registerPlugin: typeof registerPlugin;
    plugin: typeof plugin;
    requirePlugin: typeof requirePlugin;
    invoke: typeof invoke;
    whenNative: typeof whenNative;
};

export { type CapacitorBridge, type MobilePlatform, MobileUnavailableError, invoke, isNative, mobile, platform, plugin, registerPlugin, requirePlugin, whenNative };

Examples

Examples are taken from this package's installed documentation and must be evaluated with its requirements and stability notes.

Register and invoke a Capacitor plugin

import { Camera, CameraResultType } from "@capacitor/camera";
import { mobile } from "@wrnexus/mobile";

mobile.registerPlugin("Camera", Camera);

export async function takePhoto() {
  if (!mobile.isNative()) return null;
  return mobile.invoke("Camera", "getPhoto", {
    quality: 85,
    resultType: CameraResultType.Uri,
  });
}

Provide a browser fallback

import { Haptics, ImpactStyle } from "@capacitor/haptics";
import { mobile } from "@wrnexus/mobile";

mobile.registerPlugin("Haptics", Haptics);

export const confirmAction = () =>
  mobile.whenNative(
    () => mobile.invoke("Haptics", "impact", { style: ImpactStyle.Medium }),
    () => navigator.vibrate?.(30),
  );

Read an optional plugin without throwing

import type { NetworkPlugin } from "@capacitor/network";
import { mobile } from "@wrnexus/mobile";

const network = mobile.plugin<NetworkPlugin>("Network");
const status = network ? await network.getStatus() : { connected: true, connectionType: "unknown" };
} }