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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cashable/game-sdk

v0.8.5

Published

Cashable Unified Game SDK for embedded (WebView) and standalone (Capacitor) games

Readme

@ververonmedia/cashable-game-sdk

Unified TypeScript SDK for Cashable games. Provides a single API surface for both embedded (WebView inside the Cashable app) and standalone (Capacitor-wrapped APK) game modes.

Install

npm install @ververonmedia/cashable-game-sdk

Quick Start

The npm package ships only the CDN loader — a ~1KB bootstrap that loads the full SDK from CDN at runtime. This keeps the SDK out of your bundle and enables over-the-air updates. See the Game Integration Guide for a complete walkthrough.

import { loadCashableSDK } from '@ververonmedia/cashable-game-sdk/loader';
import type { CashableSDKConfig } from '@ververonmedia/cashable-game-sdk/loader';

// Load SDK from CDN
const SDK = await loadCashableSDK({ apiBaseUrl: 'https://api.cashableapp.com' });

const cashable = new SDK({
  gameId: 'smash-monsters',
  debug: true,
});

await cashable.init();

// Show a rewarded video ad
const success = await cashable.ads.showRewardedVideo();
if (success) {
  await cashable.rewards.awardCoins();
}

// Start play-time tracking
cashable.analytics.startAutoTracking();

// Clean up when done
cashable.dispose();

Babylon.js Integration

The Babylon.js plugin is auto-detected at runtime and binds your scene for automatic freeze/resume:

// After SDK is loaded and initialized via the loader:
cashable.babylon.bindScene(scene, engine);
// The SDK will automatically stop/start the render loop
// when the host app freezes/resumes the game

Modes

The SDK operates in two modes, auto-detected at runtime:

| | Embedded | Standalone | |---|---|---| | Context | WebView inside Cashable app | Capacitor-wrapped APK | | Detection | window.ReactNativeWebView exists | window.Capacitor exists | | Transport | postMessage bridge | HTTP REST calls | | Auth | Host manages identity | App Set ID via Capacitor plugin | | Ads | Host shows ads | Native AppLovin MAX plugin |

You can override detection by passing mode explicitly:

const cashable = new CashableSDK({
  gameId: 'my-game',
  mode: 'standalone',
  apiBaseUrl: 'https://api.cashable.app',
  appLovin: {
    sdkKey: 'YOUR_SDK_KEY',
    rewardedAdUnitId: 'YOUR_REWARDED_AD_UNIT_ID',
    interstitialAdUnitId: 'YOUR_INTERSTITIAL_AD_UNIT_ID',
    bannerAdUnitId: 'YOUR_BANNER_AD_UNIT_ID',
  },
  ui: {
    onClose: () => Capacitor.Plugins.App.exitApp(),
  },
});

Configuration

interface CashableSDKConfig {
  /** Unique game identifier */
  gameId: string;
  /** Force a specific mode instead of auto-detecting */
  mode?: 'embedded' | 'standalone';
  /** Backend API base URL (standalone mode only) */
  apiBaseUrl?: string;
  /** Request timeout in milliseconds (default: 10000) */
  requestTimeoutMs?: number;
  /** Enable debug logging (default: false) */
  debug?: boolean;
  /** AppLovin MAX config (required for standalone mode ads) */
  appLovin?: {
    /** SDK key from AppLovin dashboard (Account > General > Keys) */
    sdkKey: string;
    rewardedAdUnitId: string;
    interstitialAdUnitId: string;
    /** Optional - omit to disable banner ads */
    bannerAdUnitId?: string;
  };
  /** UI config for standalone mode */
  ui?: {
    onClose?: () => void;      // Close button callback
    onMenuOpen?: () => void;   // Menu button callback (optional)
    showCashableButton?: boolean; // Show floating panel button (default: false)
    cashableButton?: {
      position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
    };
  };
}

Note: The appLovin and ui configs are only used in standalone mode. In embedded mode, the host Cashable app handles ads and UI.

Modules

The SDK exposes its functionality through focused modules:

| Module | Accessor | Description | |---|---|---| | Session | cashable.session | User identity, balance | | Rewards | cashable.rewards | Coin awarding | | Ads | cashable.ads | Rewarded video, interstitial & banner ads | | Analytics | cashable.analytics | Play-time tracking, theme color | | Babylon | cashable.babylon | Babylon.js render loop freeze/resume | | Feature Flags | cashable.featureFlags | Remote config, feature gates, event logging (Statsig) | | UI | cashable.ui | Floating panel, sponsored modal, offers, tier celebrations (standalone only) |

Authentication

Embedded mode: The host Cashable app handles all authentication. The SDK is always considered authenticated (cashable.isAuthenticated === true).

Standalone mode: The SDK reads the device's App Set ID via a Capacitor plugin and sends it as X-App-Set-Id header. The backend maps this to a known user if the user has previously opened the game in the Cashable app. If no mapping exists, cashable.isAuthenticated is false and coin-related features will fail gracefully.

if (cashable.isAuthenticated) {
  const { coins } = await cashable.session.getBalance();
  console.log(`User has ${coins} coins`);
} else {
  console.log('User not linked - coin features unavailable');
}

Lifecycle Events

// Called when the host app puts the game in the background
cashable.onFreeze(() => {
  // Pause game logic, audio, etc.
});

// Called when the host app brings the game back
cashable.onResume(() => {
  // Resume game logic, audio, etc.
});

If you've bound a Babylon.js scene, the render loop is automatically stopped/started for you.

Error Handling

SDK errors include a code property for programmatic handling:

| Code | Meaning | |---|---| | TIMEOUT | Request timed out | | TRANSPORT_ERROR | Communication layer failure | | AD_NOT_AVAILABLE | No ad fill available | | NETWORK_ERROR | HTTP request failed | | USER_NOT_LINKED | Standalone user has no Cashable account mapping |

try {
  await cashable.rewards.awardCoins();
} catch (err) {
  if (err.code === 'USER_NOT_LINKED') {
    // User hasn't opened this game in the Cashable app yet
  }
}

Cleanup

Always call dispose() when the SDK is no longer needed:

cashable.dispose();

This stops analytics tracking, removes event listeners, aborts pending requests, and cleans up the Babylon.js plugin.

Top-Level Convenience APIs

CashableSDK.getWidgetHeight(): number (static)

Computes the widget top-bar height from window.innerWidth alone — no DOM or init() required. Call it at script load time to offset your game canvas immediately:

const height = CashableSDK.getWidgetHeight();
game.setTopOffset(height);

Also available as a standalone function from both entry points:

// CDN / main entry
import { getWidgetHeight } from '@ververonmedia/cashable-game-sdk';

// Loader entry (works before CDN script loads)
import { getWidgetHeight } from '@ververonmedia/cashable-game-sdk/loader';

cashable.onWidgetReady(handler): () => void

Fires after init() mounts the UI with the exact DOM-measured height. Use it to refine the initial estimate:

sdk.onWidgetReady(({ height }) => {
  game.setTopOffset(height); // update with real value
});

cashable.getTopBarHeight(): number

Returns the pixel height of the SDK's top bar. Before init() completes, falls back to CashableSDK.getWidgetHeight() (computed estimate). After init(), returns the real DOM-measured value.

const offset = cashable.getTopBarHeight();
gameCanvas.style.marginTop = `${offset}px`;

cashable.adConfig: Readonly<AdConfig>

Returns the current ad configuration with Statsig remote overrides merged on top of defaults. Shorthand for cashable.featureFlags?.adConfig ?? DEFAULT_AD_CONFIG.

const cooldown = cashable.adConfig.interstitialCooldownMs;

See AdConfig for all available fields.

Standalone UI

In standalone mode, when the user is authenticated, the SDK renders a floating CashableButton that opens a panel with rewards info, cashout flow, and games. It also provides sponsored video modals for interstitials and bonus/booster offer modals.

See the full UI Module documentation for all methods, components, and behavior details.

CashableButton Panel

Shown automatically after init() when showCashableButton: true. The panel has three content areas:

  • Rewards tab (main screen) — coins pill, tier card with progress bar, "Convert coins to real money" CTA, partners section
  • Cashout screen (sub-screen) — countdown timer, earnings display, cashout button, partners. Accessed via the CTA button; back button returns to main screen
  • Games tab — lists available games

The panel trigger row displays the current coin balance with earn animations, inline countdown timer, and offer countdown badges.

Sponsored Interstitial

// Show a 3-second countdown modal, then the interstitial ad
const success = await cashable.ui?.showSponsoredInterstitial();

Shows an animated countdown, then the ad, then a success/failure state. Coins are automatically awarded on success with the current boost multiplier applied.

Bonus & Booster Offers

The SDK periodically shows bonus coin offers and 2x boost offers via the OfferScheduler. When an offer triggers, a 20-second countdown badge appears on the panel trigger. If the user taps within the countdown, the corresponding modal opens (rewarded ad required to claim).

Controlling the UI

cashable.ui?.updateCoins(newBalance);          // Manually update displayed coins
cashable.ui?.updateThemeColor('#1a1a2e');       // Change panel background
await cashable.ui?.refreshWallet();             // Re-fetch wallet data from backend

cashable.ui is null in embedded mode or when the user is not authenticated.

Testing on Device

The SDK ships with two Android test targets for on-device testing. Both reference the SDK as a local file: dependency, so they always pick up the latest build.

| Target | Directory | App ID | Description | |--------|-----------|--------|-------------| | test-app | debug/ | com.ververon.monster | Minimal SDK debug harness | | test-game | debug/test-game/block-blast/Block-Blast/ | com.ververon.monster | Block Blast game with full SDK integration |

Prerequisites

  • Android device connected via USB with ADB debugging enabled
  • Java 21 available (JAVA_HOME=$(/usr/libexec/java_home -v 21))

Quick Start

# 1. Build the SDK
cd cashable-game-sdk && npm run build

# 2a. Deploy test-app (convenience script)
cd debug
JAVA_HOME=$(/usr/libexec/java_home -v 21) npm run run:android

# 2b. Deploy test-game (Block Blast)
cd debug/test-game/block-blast/Block-Blast
npm run build
npx cap sync android
cd android && JAVA_HOME=$(/usr/libexec/java_home -v 21) ./gradlew assembleDebug && cd ..
adb install -r android/app/build/outputs/apk/debug/app-debug.apk

APK Location

After building, the debug APK is at:

  • test-app: debug/android/app/build/outputs/apk/debug/app-debug.apk
  • test-game: debug/test-game/block-blast/Block-Blast/android/app/build/outputs/apk/debug/app-debug.apk

Claude Code Skill

The sdk-android-test skill automates the full build-and-deploy flow. Invoke it with /sdk-android-test in Claude Code to build the SDK and deploy to a connected device.

Versioning

This package has two independent version tracks:

| Version | File | What it tracks | When to bump | |---------|------|---------------|--------------| | npm (loader + types) | package.json "version" | Loader code, type declarations, native plugins | Loader logic or exported types change | | CDN (SDK runtime) | cdn-version.json "version" | Full SDK IIFE bundle served from CDN | SDK runtime code changes |

The npm package ships only the loader (~1KB bootstrap) and type declarations. The full SDK runtime is built separately and deployed to CDN (cashableapp.com/sdk/v<CDN_VERSION>/cashable-sdk.js). At runtime, the loader fetches the SDK version from the backend and loads the IIFE bundle from CDN.

A CDN deploy does not require an npm publish, and vice versa.

API Reference