Skip to main content

miniapp-sdk - SDK for Mini-Apps

SDK that provides APIs for mini-apps to communicate with the host app through the bridge protocol.

Installation

pnpm add @54vie/miniapp-sdk

Quick Start

import {
useHostAuth,
useHostDevice,
storage,
analytics,
} from '@54vie/miniapp-sdk';

function MiniApp() {
const { user, isAuthenticated } = useHostAuth();
const { deviceInfo } = useHostDevice();

useEffect(() => {
analytics.screen('MiniAppHome');
}, []);

if (!isAuthenticated) {
return <LoginPrompt />;
}

return <MainContent user={user} />;
}

Authentication

useHostAuth

import { useHostAuth } from '@54vie/miniapp-sdk';

function ProfileScreen() {
const {
user, // Current user object
isAuthenticated, // Boolean
isLoading, // Loading state
accessToken, // JWT token for API calls
requestLogin, // Trigger host login flow
checkPermission, // Check specific permission
} = useHostAuth();

if (!isAuthenticated) {
return (
<View>
<Text>Please login to continue</Text>
<Button onPress={requestLogin}>Login</Button>
</View>
);
}

return (
<View>
<Text>Welcome, {user.name}!</Text>
<Text>Email: {user.email}</Text>
</View>
);
}

API with Auth

import { useHostAuth, api } from '@54vie/miniapp-sdk';

function OrderList() {
const { accessToken } = useHostAuth();

const fetchOrders = async () => {
// Token is automatically injected by the bridge
const orders = await api.get('/orders');
return orders;
};
}

Storage

import { storage } from '@54vie/miniapp-sdk';

// Get value
const value = await storage.get('my-key');

// Set value
await storage.set('my-key', { data: 'value' });

// Remove
await storage.remove('my-key');

// Clear all (within mini-app scope)
await storage.clear();
Storage Scope

Each mini-app has its own isolated storage namespace. Data from one mini-app cannot be accessed by another.

Device Information

useHostDevice

import { useHostDevice } from '@54vie/miniapp-sdk';

function MyComponent() {
const {
model, // "iPhone 15 Pro"
brand, // "Apple"
os, // "ios" | "android"
osVersion, // "17.0"
appVersion, // "1.0.0"
isEmulator, // Boolean
isTablet, // Boolean
} = useHostDevice();

return (
<Text>Running on {brand} {model}</Text>
);
}

Direct Access

import { device } from '@54vie/miniapp-sdk';

const info = await device.getInfo();
const deviceId = await device.getDeviceId();
const isEmulator = await device.isEmulator();

Network Status

import { useHostNetwork, network } from '@54vie/miniapp-sdk';

// Hook
function MyComponent() {
const {
isOnline,
isWifi,
isCellular,
connectionType, // 'wifi' | 'cellular' | 'none'
} = useHostNetwork();

if (!isOnline) {
return <OfflineMessage />;
}
}

// Direct
const isOnline = await network.isOnline();
const type = await network.getConnectionType();

Analytics

import { analytics } from '@54vie/miniapp-sdk';

// Track event
analytics.track('button_clicked', {
button_name: 'checkout',
product_id: '123',
});

// Track screen
analytics.screen('ProductDetail', {
product_id: '123',
});
Attribution

All events from mini-apps are automatically attributed to the mini-app ID for analytics purposes.

Push Notifications

import { useHostPush, push } from '@54vie/miniapp-sdk';

// Hook
function NotificationSettings() {
const {
hasPermission,
token,
requestPermission,
} = useHostPush();

if (!hasPermission) {
return (
<Button onPress={requestPermission}>
Enable Notifications
</Button>
);
}
}

// Direct
const token = await push.getToken();
await push.subscribeToTopic('promotions');
await push.scheduleNotification({
title: 'Reminder',
body: 'Your order is ready!',
scheduledAt: new Date(Date.now() + 3600000),
});

Location

import { useHostLocation, location } from '@54vie/miniapp-sdk';

// Hook
function NearbyStores() {
const {
currentLocation,
isLoading,
error,
hasPermission,
requestPermission,
} = useHostLocation();

if (!hasPermission) {
return <Button onPress={requestPermission}>Allow Location</Button>;
}

if (isLoading) return <Loading />;

return <StoreList location={currentLocation} />;
}

// Direct
const position = await location.getCurrentPosition();
const address = await location.reverseGeocode(position.latitude, position.longitude);
const places = await location.searchPlaces('coffee shop', position);

Media

import { media } from '@54vie/miniapp-sdk';

// Take photo
const photo = await media.takePhoto({
quality: 'high',
cameraType: 'back',
});

// Pick from gallery
const images = await media.pickImage({
multiple: true,
maxSelection: 5,
});

// Crop image
const cropped = await media.cropImage(photo.uri, {
width: 300,
height: 300,
aspectRatio: 1,
});

// Resize
const resized = await media.resizeImage(photo.uri, {
width: 800,
quality: 0.8,
});

UI Services

Toast

import { ui } from '@54vie/miniapp-sdk';

ui.showToast({
message: 'Saved successfully!',
type: 'success',
});

ui.showToast({
message: 'Something went wrong',
type: 'error',
});

Alert

import { ui } from '@54vie/miniapp-sdk';

const result = await ui.showAlert({
title: 'Confirm',
message: 'Are you sure you want to delete?',
buttons: [
{ text: 'Cancel', style: 'cancel' },
{ text: 'Delete', style: 'destructive' },
],
});

if (result === 1) {
// User pressed Delete
}

Action Sheet

import { ui } from '@54vie/miniapp-sdk';

const result = await ui.showActionSheet({
title: 'Choose action',
options: [
{ label: 'Share', icon: 'share' },
{ label: 'Edit', icon: 'edit' },
{ label: 'Delete', icon: 'trash', destructive: true },
],
cancelLabel: 'Cancel',
});

Haptics

import { haptics } from '@54vie/miniapp-sdk';

// Impact feedback
haptics.impact('light'); // light, medium, heavy
haptics.impact('medium');

// Notification feedback
haptics.notification('success'); // success, warning, error

// Selection feedback
haptics.selection();

Clipboard

import { clipboard } from '@54vie/miniapp-sdk';

// Copy
await clipboard.setString('Hello World');

// Paste
const text = await clipboard.getString();

// Check
const hasContent = await clipboard.hasString();

Share

import { share } from '@54vie/miniapp-sdk';

// Share text
await share.text({
message: 'Check out this product!',
url: 'https://54vie.vn/product/123',
title: 'Share Product',
});

// Share image
await share.image({
imageUrl: 'file:///path/to/image.jpg',
message: 'My photo',
});
import { navigation } from '@54vie/miniapp-sdk';

// Navigate to host screen
navigation.navigate('Wallet');

// Go back
navigation.goBack();

// Open another mini-app
navigation.openMiniApp('com.54vie.booking', {
serviceId: '123',
});

API Requests

import { api } from '@54vie/miniapp-sdk';

// Requests are proxied through host with auth
const products = await api.get('/products');
const order = await api.post('/orders', orderData);
Rate Limiting

API requests from mini-apps are subject to rate limiting. Default is 100 requests per minute.

Permissions

Mini-apps must declare required permissions in manifest.json:

{
"appId": "com.54vie.shopping",
"name": "Shopping",
"permissions": [
"storage",
"analytics",
"push",
"location",
"camera"
]
}

Check permission at runtime:

import { useHostAuth } from '@54vie/miniapp-sdk';

function CameraFeature() {
const { checkPermission, requestPermission } = useHostAuth();

const handleCamera = async () => {
const hasPermission = await checkPermission('camera');
if (!hasPermission) {
const granted = await requestPermission('camera', 'Need camera for scanning');
if (!granted) return;
}
// Use camera
};
}