npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@appboxo/web-sdk

v1.4.0

Published

Boxo Desktop Host App SDK for handling miniapp events

Readme

Appboxo Web SDK

Embed miniapps into your desktop application using iframe communication.

Quick Start

import { AppboxoWebSDK } from "@appboxo/web-sdk";

const sdk = new AppboxoWebSDK({
  clientId: "your-client-id",
  appId: "your-app-id"
});

// Get auth code from your backend
const authCode = await fetch('/api/auth-code').then(r => r.json());
sdk.setAuthCode(authCode);

// Mount miniapp
await sdk.mount({
  container: document.getElementById("miniapp"),
  url: "https://your-miniapp.com"
});

// Or let SDK fetch URL from API automatically
await sdk.mount({
  container: document.getElementById("miniapp")
});

Installation

npm install @appboxo/web-sdk
# or
pnpm install @appboxo/web-sdk

Configuration

const sdk = new AppboxoWebSDK({
  clientId: string;      // Required
  appId: string;         // Required
  userId?: string;       // Optional, user reference identifier
  baseUrl?: string;      // Optional, default: "https://dashboard.boxo.io/api/v1"
  sandboxMode?: boolean;  // Optional, default: false
  debug?: boolean;       // Optional, default: false. When true, enables all console logs for debugging. When false, no console logs are output.
  locale?: string;       // Optional, locale/language code (e.g., 'en', 'en-US', 'ru', 'zh-CN')
  isDesktop?: boolean;   // Optional, default: false. When true, API calls to fetch miniapp settings will include is_desktop=true parameter
  onGetAuthCode?: () => Promise<string>; // Optional, for automatic auth code retrieval
  onGetAuthTokens?: () => Promise<LoginResponse>; // Optional, for direct auth tokens
  onPaymentRequest?: (params: PaymentRequest) => Promise<PaymentResponse>; // Optional, for handling payment requests
});

Authentication

OAuth flow:

sdk.setAuthCode(authCode);

Or provide a callback:

const sdk = new AppboxoWebSDK({
  clientId: "your-client-id",
  appId: "your-app-id",
  onGetAuthCode: async () => {
    const res = await fetch('/api/generate-auth-code');
    return (await res.json()).auth_code;
  }
});

Direct auth flow:

sdk.onAuth(async () => {
  const response = await fetch('/api/get-miniapp-tokens');
  const tokens = await response.json();
  sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);
});

Or use callback:

const sdk = new AppboxoWebSDK({
  clientId: "your-client-id",
  appId: "your-app-id",
  onGetAuthTokens: async () => {
    const res = await fetch('/api/get-miniapp-tokens');
    const result = await res.json();
    return {
      token: result.access_token,
      refresh_token: result.refresh_token
    };
  }
});

Or set tokens directly:

const tokens = await getTokensFromBackend();
sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);

The SDK will try these in order:

  1. Pre-set tokens (setAuthTokens)
  2. Direct auth callback (onGetAuthTokens)
  3. OAuth auth code (setAuthCode or onGetAuthCode callback)

Payment Processing

When a miniapp calls appboxo.pay(), the SDK will call your onPaymentRequest callback. Process the payment and return the result.

Payment status values: 'success', 'failed', or 'cancelled'.

const sdk = new AppboxoWebSDK({
  clientId: "your-client-id",
  appId: "your-app-id",
  onPaymentRequest: async (paymentData) => {
    // Process payment with your backend
    const response = await fetch('/api/payments/process', {
      method: 'POST',
      body: JSON.stringify(paymentData)
    });
    const result = await response.json();
    
    return {
      ...paymentData,
      status: result.status, // 'success', 'failed', or 'cancelled'
      hostappOrderId: result.orderId,
      transactionId: result.transactionId, // optional
    };
  },
});

// Optional: listen for payment completion
sdk.onPaymentComplete((success, data) => {
  if (success) {
    console.log('Payment succeeded:', data);
  }
});

Important Notes:

  • When onPaymentRequest is set, the SDK automatically tells the miniapp it supports AppBoxoWebAppPay, so it can call appboxo.pay().
  • If onPaymentRequest is not configured, payment requests will fail. Enable debug: true to see error messages.
  • About debug mode:
    • debug: false (default): No console logs are output. Suitable for production.
    • debug: true: All SDK operations are logged to console. Useful for development and troubleshooting.
    • The debug option does not affect SDK functionality - it only controls console logging.

Locale/Language

Set the locale/language code to pass to the miniapp. The locale will be included in the InitData response.

// Set locale during initialization
const sdk = new AppboxoWebSDK({
  clientId: "your-client-id",
  appId: "your-app-id",
  locale: "en-US"  // or 'ru', 'zh-CN', etc.
});

// Or set locale dynamically
sdk.setLocale("ru");

The locale is passed to the miniapp via InitData.data.locale on the next AppBoxoWebAppGetInitData request.

Important Notes:

  • If you call setLocale() after the miniapp has already loaded, the locale will be included in the next InitData request. The miniapp may need to reload or request InitData again to receive the updated locale.
  • To ensure the locale is available immediately, set it during SDK initialization or before calling mount().

Desktop Mode

When isDesktop: true is set, the SDK will include is_desktop=true parameter when fetching miniapp settings from the API. This allows the backend to return desktop-specific configurations.

const sdk = new AppboxoWebSDK({
  clientId: "your-client-id",
  appId: "your-app-id",
  isDesktop: true  // Enable desktop mode
});

When enabled, API calls to /miniapps/{appId}/settings/ will include the is_desktop=true query parameter:

GET /miniapps/{appId}/settings/?client_id={clientId}&is_desktop=true

Logout

The logout() method clears the host app's storage and SDK's internal authentication data.

sdk.logout();

Important Notes:

  • This only clears the host app's localStorage and sessionStorage
  • Miniapp's storage is separate (different origin) and cannot be cleared from the host app due to browser security restrictions
  • The SDK will send a logout notification to the miniapp via postMessage using the standard appboxo-host-response format
  • Miniapp should listen for AppBoxoWebAppLogout handler to clear its own storage
  • SDK's internal authCode and authTokens are also cleared

Miniapp Integration:

To receive logout notifications in your miniapp, add a message listener:

useEffect(() => {
  const handleMessage = (event: MessageEvent) => {
    if (
      event.data?.type === "appboxo-host-response" &&
      event.data?.handler === "AppBoxoWebAppLogout" &&
      event.data?.data?.action === "logout"
    ) {
      // Clear miniapp's storage
      localStorage.clear();
      sessionStorage.clear();
    }
  };
  
  window.addEventListener("message", handleMessage);
  return () => window.removeEventListener("message", handleMessage);
}, []);

Methods

| Method | Description | |--------|-------------| | setAuthCode(code) | Set authentication code | | setAuthTokens(token, refreshToken?) | Set authentication tokens directly | | setLocale(locale) | Set locale/language code (e.g., 'en', 'en-US', 'ru', 'zh-CN') | | onAuth(callback) | Register callback for authentication events | | mount(config) | Create iframe and initialize SDK | | getMiniappUrl() | Fetch miniapp URL from API settings endpoint | | setIframe(iframe) | Set iframe element manually | | initialize() | Start listening for events | | onEvent(type, handler) | Register custom event handler | | onLoginComplete(callback) | Login completion callback | | onPaymentComplete(callback) | Payment completion callback | | logout() | Clear host app's localStorage, sessionStorage, and SDK's internal auth data | | destroy() | Clean up resources |

Events

SDK handles these miniapp events:

  • AppBoxoWebAppLogin - User authentication
  • AppBoxoWebAppPay - Payment processing
  • AppBoxoWebAppGetInitData - Initial data request
  • AppBoxoWebAppCustomEvent - Custom events

Examples

React Example

import { AppboxoWebSDK } from "@appboxo/web-sdk";
import type { PaymentRequest, PaymentResponse } from "@appboxo/web-sdk";

function App() {
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const [sdk, setSdk] = useState<AppboxoWebSDK | null>(null);

  useEffect(() => {
    const s = new AppboxoWebSDK({ 
      clientId: "your-client-id", 
      appId: "your-app-id",
      onPaymentRequest: async (paymentData: PaymentRequest): Promise<PaymentResponse> => {
        const response = await fetch('/api/payments/process', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(paymentData)
        });
        const result = await response.json();
        
        return {
          ...paymentData,
          status: result.status,
          hostappOrderId: result.hostappOrderId,
        };
      },
    });
    
    s.setAuthCode("your-auth-code");
    
    s.onLoginComplete((success, data) => {
      console.log('Login:', success ? 'success' : 'failed', data);
    });
    s.onPaymentComplete((success, data) => {
      console.log('Payment:', success ? 'success' : 'failed', data);
    });
    
    setSdk(s);
    return () => s.destroy();
  }, []);

  useEffect(() => {
    const fetchUrl = async () => {
      if (sdk && iframeRef.current) {
        const url = await sdk.getMiniappUrl();
        iframeRef.current.src = url;
      }
    };
    fetchUrl();
  }, [sdk]);

  const handleLoad = () => {
    if (sdk && iframeRef.current) {
      sdk.setIframe(iframeRef.current);
      sdk.initialize();
    }
  };

  return <iframe ref={iframeRef} onLoad={handleLoad} src="" />;
}

Using mount helper

// With explicit URL
await sdk.mount({
  container: '#miniapp-container',
  url: 'https://miniapp.com',
  className: 'miniapp-iframe'
});

// Or fetch URL from API automatically
await sdk.mount({
  container: '#miniapp-container',
  className: 'miniapp-iframe'
});

Styling is handled via CSS:

.miniapp-container {
  width: 100%;
  height: 500px;
}

.miniapp-iframe {
  width: 100%;
  height: 100%;
  border: none;
}

License

Apache-2.0