Skip to main content

Services API

The @54vie/miniapp-sdk provides singleton service instances that allow mini-apps to access host app capabilities. These services communicate with the host app through the bridge layer.

storage

Persistent key-value storage service for mini-apps.

TypeScript Interface

interface StorageService {
/**
* Set storage scope/namespace
*/
setScope(scope: string): void;

/**
* Get a value by key
* @returns The stored value or null if not found
*/
get<T = unknown>(key: string): Promise<T | null>;

/**
* Set a value for a key
*/
set<T = unknown>(key: string, value: T): Promise<void>;

/**
* Remove a value by key
*/
remove(key: string): Promise<void>;

/**
* Clear all storage in the current scope
*/
clear(): Promise<void>;

/**
* Get multiple values at once
* @returns Object mapping keys to their values
*/
getMultiple<T = unknown>(keys: string[]): Promise<Record<string, T | null>>;

/**
* Set multiple values at once
*/
setMultiple<T = unknown>(items: Record<string, T>): Promise<void>;
}

Example

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

// Set a namespace for your mini-app data
storage.setScope('my-miniapp');

// Store simple values
await storage.set('theme', 'dark');
await storage.set('language', 'vi');

// Store complex objects
await storage.set('user_preferences', {
notifications: true,
autoPlay: false,
volume: 0.8,
});

// Retrieve values with type inference
const theme = await storage.get<string>('theme');
console.log('Theme:', theme); // 'dark'

interface Preferences {
notifications: boolean;
autoPlay: boolean;
volume: number;
}
const prefs = await storage.get<Preferences>('user_preferences');
console.log('Volume:', prefs?.volume); // 0.8

// Get multiple values at once
const settings = await storage.getMultiple(['theme', 'language']);
console.log(settings); // { theme: 'dark', language: 'vi' }

// Set multiple values at once
await storage.setMultiple({
lastVisited: Date.now(),
viewCount: 42,
});

// Remove a specific key
await storage.remove('theme');

// Clear all storage in scope
await storage.clear();

Bridge Actions

ActionDescription
storage.getRetrieve a value by key
storage.setStore a value
storage.removeRemove a value
storage.clearClear all storage

device

Access device hardware information and capabilities.

TypeScript Interface

interface DeviceInfo {
deviceId: string;
deviceName: string;
platform: 'ios' | 'android';
model: string;
brand: string;
osVersion: string;
appVersion: string;
buildNumber: string;
isEmulator: boolean;
isTablet: boolean;
}

interface DeviceService {
/**
* Get complete device information
*/
getInfo(): Promise<DeviceInfo>;

/**
* Get unique device identifier
*/
getDeviceId(): Promise<string>;

/**
* Get host app version (e.g., "1.0.0")
*/
getAppVersion(): Promise<string>;

/**
* Get host app build number
*/
getBuildNumber(): Promise<string>;

/**
* Check if running on emulator/simulator
*/
isEmulator(): Promise<boolean>;

/**
* Get mobile carrier name
*/
getCarrier(): Promise<string | null>;
}

Example

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

// Get complete device info
const info = await device.getInfo();
console.log(`Device: ${info.brand} ${info.model}`);
console.log(`Platform: ${info.platform} ${info.osVersion}`);
console.log(`App Version: ${info.appVersion} (${info.buildNumber})`);

// Check specific properties
const deviceId = await device.getDeviceId();
console.log('Device ID:', deviceId);

const isEmulator = await device.isEmulator();
if (isEmulator) {
console.log('Running on emulator - some features may be limited');
}

// Get carrier info for mobile networks
const carrier = await device.getCarrier();
if (carrier) {
console.log('Carrier:', carrier);
}

// Check app version for feature flags
const version = await device.getAppVersion();
if (semver.gte(version, '2.0.0')) {
// Enable new feature
}

Bridge Actions

ActionDescription
device.getInfoGet full device information
device.getDeviceIdGet device identifier
device.getAppVersionGet host app version
device.getBuildNumberGet host app build number
device.isEmulatorCheck if emulator
device.getCarrierGet carrier name

network

Check network connectivity and connection type.

TypeScript Interface

type ConnectionType = 'wifi' | 'cellular' | 'none' | 'unknown';

interface NetworkState {
isConnected: boolean;
isInternetReachable: boolean;
type: ConnectionType;
isWifi: boolean;
isCellular: boolean;
cellularGeneration?: '2g' | '3g' | '4g' | '5g';
}

interface NetworkService {
/**
* Get full network state
*/
getState(): Promise<NetworkState>;

/**
* Check if device is online
*/
isOnline(): Promise<boolean>;

/**
* Get current connection type
*/
getConnectionType(): Promise<ConnectionType>;

/**
* Check if connected via WiFi
*/
isWifi(): Promise<boolean>;

/**
* Check if connected via cellular
*/
isCellular(): Promise<boolean>;
}

Example

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

// Quick online check
const isOnline = await network.isOnline();
if (!isOnline) {
showOfflineMessage();
return;
}

// Get detailed network state
const state = await network.getState();
console.log('Connection type:', state.type);
console.log('Internet reachable:', state.isInternetReachable);

if (state.cellularGeneration) {
console.log('Cellular generation:', state.cellularGeneration);
}

// Optimize for connection type
const isWifi = await network.isWifi();
if (isWifi) {
// Download high-res images
downloadHighResAssets();
} else {
// Use compressed images on cellular
downloadCompressedAssets();
}

// Warn user on slow connection
if (state.cellularGeneration === '2g' || state.cellularGeneration === '3g') {
showSlowConnectionWarning();
}

Bridge Actions

ActionDescription
network.getStateGet full network state
network.isOnlineCheck if online
network.getConnectionTypeGet connection type
network.isWifiCheck if WiFi
network.isCellularCheck if cellular

push

Manage push notifications and local notifications.

TypeScript Interface

interface LocalNotification {
id?: string;
title: string;
body: string;
data?: Record<string, unknown>;
/** Schedule date (ISO string or timestamp) */
fireDate?: string | number;
/** Repeat interval */
repeatType?: 'minute' | 'hour' | 'day' | 'week' | 'month';
/** Badge number */
badge?: number;
/** Sound name */
sound?: string;
/** Android channel ID */
channelId?: string;
}

interface PushService {
/**
* Get FCM/APNs push token
*/
getToken(): Promise<string | null>;

/**
* Check if notification permission is granted
*/
hasPermission(): Promise<boolean>;

/**
* Request notification permission
*/
requestPermission(): Promise<boolean>;

/**
* Subscribe to a topic (FCM)
*/
subscribeToTopic(topic: string): Promise<void>;

/**
* Unsubscribe from a topic
*/
unsubscribeFromTopic(topic: string): Promise<void>;

/**
* Schedule a local notification
* @returns Notification ID
*/
scheduleNotification(notification: LocalNotification): Promise<string>;

/**
* Cancel a scheduled notification
*/
cancelNotification(notificationId: string): Promise<void>;

/**
* Get current badge count
*/
getBadgeCount(): Promise<number>;

/**
* Set badge count
*/
setBadgeCount(count: number): Promise<void>;

/**
* Clear badge (set to 0)
*/
clearBadge(): Promise<void>;
}

Example

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

// Request notification permission
const hasPermission = await push.requestPermission();
if (!hasPermission) {
console.log('User denied notification permission');
return;
}

// Get push token for server registration
const token = await push.getToken();
if (token) {
await api.registerDevice({ token, platform: 'ios' });
}

// Subscribe to topics for targeted notifications
await push.subscribeToTopic('order_updates');
await push.subscribeToTopic('promotions');
await push.subscribeToTopic(`user_${userId}`);

// Schedule a local notification
const notificationId = await push.scheduleNotification({
title: 'Order Ready',
body: 'Your order #12345 is ready for pickup!',
fireDate: Date.now() + 3600000, // 1 hour from now
sound: 'default',
badge: 1,
data: {
orderId: '12345',
action: 'pickup',
},
});

// Schedule a repeating notification
await push.scheduleNotification({
title: 'Daily Reminder',
body: 'Check out today\'s deals!',
fireDate: new Date().setHours(9, 0, 0, 0), // 9 AM
repeatType: 'day',
});

// Cancel a scheduled notification
await push.cancelNotification(notificationId);

// Manage badge count
await push.setBadgeCount(5);
const badgeCount = await push.getBadgeCount();
console.log('Current badge:', badgeCount);
await push.clearBadge();

// Unsubscribe from topic
await push.unsubscribeFromTopic('promotions');

Bridge Actions

ActionDescription
push.getTokenGet FCM/APNs token
push.hasPermissionCheck notification permission
push.requestPermissionRequest notification permission
push.subscribeToTopicSubscribe to FCM topic
push.unsubscribeFromTopicUnsubscribe from topic
push.scheduleNotificationSchedule local notification
push.cancelNotificationCancel scheduled notification
push.getBadgeCountGet badge count
push.setBadgeCountSet badge count

analytics

Track events and screen views for analytics.

TypeScript Interface

interface AnalyticsService {
/**
* Track a custom event with properties
*/
track(eventName: string, properties?: Record<string, unknown>): void;

/**
* Track a screen view
*/
screen(screenName: string): void;
}

Example

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

// Track screen views
analytics.screen('HomeScreen');
analytics.screen('ProductDetailScreen');

// Track user actions
analytics.track('button_clicked', {
button_name: 'add_to_cart',
screen: 'ProductDetail',
});

// Track e-commerce events
analytics.track('product_viewed', {
product_id: 'SKU123',
product_name: 'Wireless Earbuds',
category: 'Electronics',
price: 1500000,
currency: 'VND',
});

analytics.track('add_to_cart', {
product_id: 'SKU123',
quantity: 2,
cart_value: 3000000,
});

analytics.track('purchase_completed', {
order_id: 'ORD-12345',
total: 3000000,
currency: 'VND',
items: [
{ product_id: 'SKU123', quantity: 2 },
],
payment_method: 'wallet',
});

// Track errors
analytics.track('error_occurred', {
error_type: 'network',
error_message: 'Failed to load products',
screen: 'ProductList',
});

Bridge Actions

ActionDescription
analytics.trackTrack custom event
analytics.screenTrack screen view

api

Make authenticated API requests through the host app proxy.

TypeScript Interface

interface ApiRequestOptions {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
headers?: Record<string, string>;
body?: unknown;
timeout?: number;
}

interface ApiResponse<T = unknown> {
data: T;
status: number;
headers: Record<string, string>;
}

interface ApiService {
/**
* Make an API request through the host app
* Authorization header is automatically added
*/
request<T = unknown>(
url: string,
options?: ApiRequestOptions
): Promise<ApiResponse<T>>;

/**
* Shorthand for GET request
*/
get<T = unknown>(url: string, options?: ApiRequestOptions): Promise<ApiResponse<T>>;

/**
* Shorthand for POST request
*/
post<T = unknown>(url: string, body?: unknown, options?: ApiRequestOptions): Promise<ApiResponse<T>>;

/**
* Shorthand for PUT request
*/
put<T = unknown>(url: string, body?: unknown, options?: ApiRequestOptions): Promise<ApiResponse<T>>;

/**
* Shorthand for DELETE request
*/
delete<T = unknown>(url: string, options?: ApiRequestOptions): Promise<ApiResponse<T>>;
}

Example

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

// GET request
const response = await api.get<Product[]>('/api/products');
console.log('Products:', response.data);

// GET with query params
const searchResults = await api.get<Product[]>('/api/products?category=electronics&limit=10');

// POST request
const newOrder = await api.post<Order>('/api/orders', {
items: [
{ productId: 'SKU123', quantity: 2 },
],
shippingAddress: {
street: '123 Main St',
city: 'Ho Chi Minh',
},
});
console.log('Order created:', newOrder.data.id);

// PUT request
const updatedProfile = await api.put<User>('/api/user/profile', {
name: 'John Doe',
phone: '+84123456789',
});

// DELETE request
await api.delete('/api/cart/items/123');

// Request with custom headers
const response = await api.request<Data>('/api/data', {
method: 'GET',
headers: {
'X-Custom-Header': 'value',
},
timeout: 10000,
});

// Handle errors
try {
const data = await api.get('/api/protected');
} catch (error) {
if (error.status === 401) {
// Token expired, user needs to re-authenticate
} else if (error.status === 403) {
// Permission denied
}
}

Bridge Actions

ActionDescription
api.requestMake an authenticated API request
Authentication

All API requests made through the api service automatically include the user's authentication token. The host app handles token refresh and retry logic.


Service Imports

All services are exported from the main package:

import {
storage,
device,
network,
push,
analytics,
api,
// Additional services
haptics,
clipboard,
location,
media,
} from '@54vie/miniapp-sdk';

For detailed hook-based alternatives, see the Hooks API documentation.