Quick Start
Step 1: Install the SDK
npm install @aisahub/app-builder-sdkOr import directly in your JavaScript modules
Step 2: Check Environment
import AppBridge from '@aisahub/app-builder-sdk';
if (AppBridge.isInApp()) {
console.log('Running in app environment');
// Use native features
} else {
console.log('Running in web browser');
// Use web alternatives
}Step 3: Use the Promise-based API
// All methods return Promises with Result structure
async function setupNotifications() {
try {
const result = await AppBridge.generateFcmToken();
if (result.success && result.data) {
console.log('FCM Token:', result.data.token);
// Send to your backend
await saveTokenToBackend(result.data.token);
}
} catch (error) {
console.error('Error:', error.error);
}
}Installation
NPM Package (Recommended)
npm install @aisahub/app-builder-sdkThen import in your JavaScript/TypeScript files:
import AppBridge from '@aisahub/app-builder-sdk';
// All methods return Promises
const result = await AppBridge.generateFcmToken();Understanding the Result Interface
All SDK methods return a Promise that resolves to a standardized Result<T> interface. This provides consistent error handling and type safety across all operations.
Result Interface Structure
interface Result<T> {
success: boolean; // true if operation succeeded, false otherwise
error?: string; // Error message(present when success is false)
data?: T; // Response data(present when success is true)
}Usage Pattern
// Method 1: Check success flag
const result = await AppBridge.generateFcmToken();
if (result.success && result.data) {
console.log('Token:', result.data.token);
// Use result.data safely
} else if (result.error) {
console.error('Error:', result.error);
}
// Method 2: Try-catch for error handling
try {
const result = await AppBridge.generateFcmToken();
if (result.success && result.data) {
await sendTokenToBackend(result.data.token);
}
} catch (error) {
console.error('Failed:', error.error);
}TypeScript Support
The SDK includes full TypeScript definitions. The generic T type represents the shape of the data returned for each specific method:
// FCM Token returns {token: string}
const fcmResult: Result<{token: string}> = await AppBridge.generateFcmToken();
// Device info returns detailed device data
const deviceResult: Result<{
model: string;
manufacturer: string;
osVersion: string;
platform: string;
}> = await AppBridge.getDeviceInfo();
// Secure storage returns {key: string, value: string}
const storageResult: Result<{key: string, value: string}> =
await AppBridge.getSecure('myKey');API Reference
AppBridge.isInApp()
Check if the web app is running inside any supported app environment (native app or PWA). Use this method for most environment checks.
Returns: boolean
if (AppBridge.isInApp()) {
// Enable app features
await enablePushNotifications();
} else {
// Use web alternatives
enableEmailNotifications();
}
// For more specific checks:
AppBridge.isNativeApp() // true if Flutter WebView
AppBridge.isPWA() // true if PWA iframeAppBridge.generateFcmToken()
Request an FCM token for push notifications. Call this after user login/registration.
Returns: Promise<Result<{token: string}>>
try {
const result = await AppBridge.generateFcmToken();
if (result.success && result.data) {
console.log('FCM Token:', result.data.token);
// Send to backend
await fetch('/api/save-token', {
method: 'POST',
body: JSON.stringify({ fcm_token: result.data.token })
});
}
} catch (error) {
console.error('Error:', error.error);
}Authentication
AppBridge.notifySuccessLogin()
Notify the native app of successful authentication. Call this after user successfully logs in on the client side. The native app will handle navigation after receiving this notification.
Returns: Promise<Result<{message: string}>>
async function handleLogin(email, password) {
try {
// 1. Perform client-side login first
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
if (!response.ok) {
throw new Error('Login failed');
}
const { token, user } = await response.json();
console.log('Login successful:', user);
// 2. Handle based on environment
if (AppBridge.isInApp()) {
// Save token and user data to secure storage
await AppBridge.saveSecure('auth_token', token);
await AppBridge.saveSecure('user_data', JSON.stringify(user));
// Notify app - it will handle navigation
await AppBridge.notifySuccessLogin();
} else {
// Web browser: store token and redirect manually
localStorage.setItem('auth_token', token);
window.location.href = '/dashboard';
}
} catch (error) {
console.error('Login failed:', error);
}
}AppBridge.logout()
Logout the user and clear all session data including FCM token.
Returns: Promise<Result<{message: string}>>
try {
const result = await AppBridge.logout();
if (result.success) {
console.log('Logged out successfully');
window.location.href = '/login';
}
} catch (error) {
console.error('Logout failed:', error.error);
}AppBridge.getAppVersion()
Get the current app version and build number.
Returns: Promise<Result<{version: string, buildNumber: string}>>
const result = await AppBridge.getAppVersion();
if (result.success && result.data) {
console.log('Version:', result.data.version);
console.log('Build:', result.data.buildNumber);
}Secure Storage
AppBridge.saveSecure(key, value)
Save data to secure encrypted storage on the device.
Parameters:
key(string): Storage keyvalue(any): Value to store
Returns: Promise<Result<{key: string}>>
try {
const result = await AppBridge.saveSecure('user_preferences', JSON.stringify(prefs));
if (result.success) {
console.log('Saved successfully');
}
} catch (error) {
console.error('Save failed:', error.error);
}AppBridge.getSecure(key)
Retrieve data from secure storage.
Parameters:
key(string): Storage key
Returns: Promise<Result<{key: string, value: string}>>
try {
const result = await AppBridge.getSecure('user_preferences');
if (result.success && result.data) {
const prefs = JSON.parse(result.data.value);
console.log('Preferences:', prefs);
}
} catch (error) {
console.error('Failed to get data:', error.error);
}AppBridge.showToast(message, duration)
Show a native toast message. This method is synchronous and returns immediately.
Parameters:
message(string): Message to displayduration('short' | 'long'): Duration (default: 'short')
Returns: boolean
AppBridge.showToast('Login successful!', 'short');
AppBridge.showToast('Processing your request...', 'long');Using with Next.js
1. Install the Package
npm install @aisahub/app-builder-sdk2. Use with Async/Await in Components
'use client';
import { useAppBridge } from '@aisahub/app-builder-sdk/hooks';
import { useEffect } from 'react';
export default function MyComponent() {
const { bridge, isNativeApp, isReady } = useAppBridge();
useEffect(() => {
if (isReady && isNativeApp && bridge) {
async function setupToken() {
try {
const result = await bridge.generateFcmToken();
if (result.success && result.data) {
console.log('Token:', result.data.token);
}
} catch (error) {
console.error('Error:', error.error);
}
}
setupToken();
}
}, [isReady, isNativeApp, bridge]);
return (
<div>
{isReady ? (
<p>Running in: {isNativeApp ? 'Native App' : 'Browser'}</p>
) : (
<p>Loading...</p>
)}
</div>
);
}3. Using Specialized Hooks
import { useGenerateFcmToken, useDeviceInfo } from '@aisahub/app-builder-sdk/hooks';
function MyComponent() {
const { generateToken, loading, token, error } = useGenerateFcmToken();
const { deviceInfo } = useDeviceInfo();
return (
<div>
<p>Device: {deviceInfo?.model}</p>
<button onClick={generateToken} disabled={loading}>
{loading ? 'Generating...' : 'Get FCM Token'}
</button>
{token && <p>Token: {token}</p>}
{error && <p className="text-red-600">Error: {error}</p>}
</div>
);
}4. Direct SDK Usage
import AppBridge from '@aisahub/app-builder-sdk';
async function handleLogin() {
if (!AppBridge.isInApp()) {
console.log('Not in app environment');
return;
}
try {
// Generate FCM token
const tokenResult = await AppBridge.generateFcmToken();
if (tokenResult.success && tokenResult.data) {
// Save to backend
await saveToken(tokenResult.data.token);
}
// Save user data securely
const saveResult = await AppBridge.saveSecure('user_id', userId);
if (saveResult.success) {
console.log('User data saved');
}
} catch (error) {
console.error('Setup failed:', error.error);
}
}Best Practices
Always Check App Environment
if (AppBridge.isInApp()) {
const result = await AppBridge.generateFcmToken();
// Use app features
} else {
// Web alternative
setupEmailNotifications();
}// Will cause errors in browser
await AppBridge.generateFcmToken();Implement Timeouts for Async Operations
async function withTimeout(promise, timeoutMs = 5000) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject({
success: false,
error: 'Operation timeout'
}), timeoutMs)
);
return Promise.race([promise, timeout]);
}
try {
const result = await withTimeout(
AppBridge.generateFcmToken(),
5000
);
console.log('Success:', result);
} catch (error) {
console.error('Error or timeout:', error.error);
}// No timeout - could hang forever
const result = await AppBridge.generateFcmToken();
console.log(result);Handle Errors Gracefully
async function handleLogout() {
if (!AppBridge.isInApp()) {
console.log('Not in app environment');
return;
}
try {
const result = await AppBridge.logout();
if (result.success) {
window.location.href = '/login';
}
} catch (error) {
console.error('Logout failed:', error.error);
// Fallback: clear local data anyway
localStorage.clear();
window.location.href = '/login';
}
}// No error handling
await AppBridge.logout();
window.location.href = '/login';Access Data from Result Structure
const result = await AppBridge.generateFcmToken();
if (result.success && result.data) {
// Access nested data property
console.log('Token:', result.data.token);
await saveToken(result.data.token);
}const result = await AppBridge.generateFcmToken();
// Wrong - data is nested
console.log('Token:', result.token);Troubleshooting
Issue: AppBridge is not defined
SDK package not imported. Ensure you've installed and imported the package correctly.
// Install the package
npm install @aisahub/app-builder-sdk
// Import in your code
import AppBridge from '@aisahub/app-builder-sdk';
if (AppBridge && typeof AppBridge.isNativeApp === 'function') {
console.log('SDK loaded successfully');
initializeApp();
} else {
console.error('SDK not found');
}Issue: Promises never resolve
Ensure you're running in app environment and implement timeouts for safety.
if (!AppBridge.isInApp()) {
console.warn('Not in app environment - app features unavailable');
return;
}
// Add timeout wrapper
async function withTimeout(promise, ms = 5000) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject({ error: 'Timeout' }), ms)
);
return Promise.race([promise, timeout]);
}
try {
const result = await withTimeout(
AppBridge.generateFcmToken(),
5000
);
console.log('Success:', result);
} catch (error) {
console.error('Error or timeout:', error);
}Issue: FCM token not saving
Check backend API endpoint and network connection. Ensure you're accessing result.data.
try {
const result = await AppBridge.generateFcmToken();
console.log('FCM Result:', result);
if (result.success && result.data) {
// Access token from nested data
const response = await fetch('/api/save-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: result.data.token })
});
console.log('Backend status:', response.status);
const data = await response.json();
console.log('Backend response:', data);
}
} catch (error) {
console.error('Error:', error);
}Issue: TypeScript errors with result.data
The SDK uses a Result<T> structure. Always check result.data exists before accessing properties.
// Correct TypeScript usage
const result = await AppBridge.generateFcmToken();
// Type guard
if (result.success && result.data) {
// TypeScript knows result.data.token exists
const token: string = result.data.token;
console.log(token);
}
// Or use optional chaining
const token = result.data?.token;
if (token) {
console.log('Token:', token);
}