Documentation

View Examples →

Quick Start

Step 1: Install the SDK

npm install @aisahub/app-builder-sdk

Or 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-sdk

Then 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 iframe

AppBridge.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 key
  • value (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 display
  • duration ('short' | 'long'): Duration (default: 'short')

Returns: boolean

AppBridge.showToast('Login successful!', 'short');
AppBridge.showToast('Processing your request...', 'long');

AppBridge.share(text, url)

Open the native share dialog.

Parameters:

  • text (string): Text to share
  • url (string): URL to share (optional)

Returns: Promise<Result<{shared: boolean}>>

try {
    const result = await AppBridge.share(
        'Check out this app!',
        'https://yourapp.com'
    );
    if (result.success) {
        console.log('Shared successfully');
    }
} catch (error) {
    console.error('Share failed:', error.error);
}

Using with Next.js

1. Install the Package

npm install @aisahub/app-builder-sdk

2. 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

Good
if (AppBridge.isInApp()) {
    const result = await AppBridge.generateFcmToken();
    // Use app features
} else {
    // Web alternative
    setupEmailNotifications();
}
Bad
// Will cause errors in browser
await AppBridge.generateFcmToken();

Implement Timeouts for Async Operations

Good
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);
}
Bad
// No timeout - could hang forever
const result = await AppBridge.generateFcmToken();
console.log(result);

Handle Errors Gracefully

Good
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';
    }
}
Bad
// No error handling
await AppBridge.logout();
window.location.href = '/login';

Access Data from Result Structure

Good
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);
}
Bad
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);
}