Hyve SDK - TypeScript wrapper for Hyve game server integration
npm install @hyve-sdk/jsTypeScript SDK for web3 authentication and game integration, providing secure signature verification and utility functions.
``bash`
bun add @hyve-sdk/jsor
npm install @hyve-sdk/jsor
pnpm add @hyve-sdk/js
- Web3 Authentication: EVM signature validation and verification
- Modern & Legacy Token Support: Dual authentication token formats
- JWT Authentication: Support for JWT tokens passed via URL parameters
- API Integration: Authenticated API calls with JWT token support
- Inventory Management: Built-in methods for user inventory operations
- Telemetry Tracking: Session-based analytics and event tracking
- Billing Integration: Unified billing for web (Stripe) and native (In-App Purchases) platforms
- Ads Integration: Google H5 Games Ads support (disabled by default)
- Native Bridge: Type-safe communication with React Native WebView apps
- Logger: Environment-aware logging system with configurable log levels
- Security Utilities: Domain validation and referrer checking
- URL Parameter Parsing: Easy extraction of authentication parameters
- UUID Generation: Built-in UUID v4 generation
`typescript
import { HyveClient } from "@hyve-sdk/js";
// Initialize client
// Environment (dev/prod) is automatically detected from the parent page URL
const client = new HyveClient();
// Authenticate from URL parameters
// Extracts: hyve-token/signature, hyve-access (JWT), game-id
const authenticated = await client.authenticateFromUrl();
if (authenticated) {
console.log('User ID:', client.getUserId());
console.log('Session ID:', client.getSessionId());
console.log('Has JWT:', client.hasJwtToken());
console.log('Game ID:', client.getGameId());
}
`
Environment Detection:
The SDK automatically detects whether to use dev or prod environment by checking the parent page URL:
- Dev: marvin.dev.hyve.gg or dev.hyve.ggmarvin.hyve.gg
- Prod: or hyve.gg
You can optionally override this for testing:
`typescript`
// Only use for local testing - NOT for production code
const client = new HyveClient({
isDev: true, // Force dev mode for testing
apiBaseUrl: 'https://...' // Optional custom API URL
});
#### Parse URL Parameters
Extract authentication and game parameters from URL:
`typescript
import { parseUrlParams } from "@hyve-sdk/js";
const params = parseUrlParams(window.location.search);
// Returns:
// {
// signature: string,
// message: string,
// gameStartTab: string,
// hyveToken: string,
// platform: string,
// hyveAccess: string, // JWT token
// gameId: string // Game identifier
// }
`
#### Verify Authentication
Unified verification supporting both modern and legacy tokens:
`typescript
import { verifyAuthentication } from "@hyve-sdk/js";
const result = verifyAuthentication({
hyveToken: params.hyveToken, // Modern token format
signature: params.signature, // Legacy format
message: params.message // Legacy format
});
if (result.isValid) {
console.log('Authenticated address:', result.address);
console.log('Auth method used:', result.method); // 'modern' or 'legacy'
}
`
#### Modern Token Verification (Hyve Token)
Verify modern authentication tokens with expiration:
`typescript
import { verifyHyveToken } from "@hyve-sdk/js";
// Token format: signature.address.randomBase64.timestamp
const address = verifyHyveToken(hyveToken, 600); // 600 seconds max age
if (address) {
console.log('Valid token for address:', address);
}
`
#### Legacy Token Verification
Verify legacy signed messages with metadata:
`typescript
import { handleVerifyMessage, validateSignature } from "@hyve-sdk/js";
// Method 1: Verify message with embedded metadata
const address = handleVerifyMessage(signature, message);
// Method 2: Simple signature validation
const isValid = validateSignature(signature, message, userId);
`
#### Domain Validation
Check if current domain is allowed:
`typescript
import { isDomainAllowed } from "@hyve-sdk/js";
// Single domain
const allowed = isDomainAllowed('example.com', window.location.hostname);
// Multiple domains with wildcard support
const allowed = isDomainAllowed(
['example.com', '*.subdomain.com'],
window.location.hostname
);
// Note: localhost is always allowed
`
#### UUID Generation
Generate random UUID v4:
`typescript
import { generateUUID } from "@hyve-sdk/js";
const id = generateUUID();
`
`typescript`
// Send a user-level telemetry event
// Game ID is automatically extracted from 'game-id' URL parameter
await client.sendTelemetry(
'game', // Event location
'player', // Event category
'action', // Event action
'combat', // Event sub-category (optional)
'attack', // Event sub-action (optional)
{ // Event details - auto-stringified (optional)
button: 'attack-btn',
screenPosition: { x: 100, y: 200 },
damage: 100,
targetId: 'enemy-123',
weaponType: 'sword',
level: 3
},
'web-chrome' // Platform ID (optional)
);
Requirements:
- Requires JWT token (from hyve-access URL parameter)game-id
- Requires authenticated user
- Requires game ID (from URL parameter)
- User ID is automatically extracted from JWT (cannot be spoofed)
URL Parameters Expected:
- hyve-access - JWT authentication tokengame-id
- - Game identifier (associates all telemetry with this game)hyve-token
- or signature+message - For user authentication
Features:
- Automatically includes session_id and game_id from clientevent_details
- Objects in are auto-stringified to JSONevent_details
- Validates is valid JSON before sending (returns false if invalid)
- All events tied to authenticated user identity
`typescript
// URL: https://game.com?hyve-access=your-jwt-token&game-id=my-game
// Authenticate extracts JWT and game ID automatically
await client.authenticateFromUrl();
// Check availability
if (client.hasJwtToken()) {
console.log('JWT token:', client.getJwtToken());
console.log('Game ID:', client.getGameId());
}
`
`typescript
// GET request
const userData = await client.callApi('/api/v1/user');
// POST request with body
const result = await client.callApi('/api/v1/game/score', {
method: 'POST',
body: JSON.stringify({ score: 1000 })
});
// With TypeScript typing
interface UserData {
id: string;
username: string;
}
const user = await client.callApi
`
#### Get User Inventory
Retrieve all inventory items:
`typescript
const inventory = await client.getInventory();
console.log(Total items: ${inventory.total_count});${item.item_type}: ${item.quantity}x
inventory.items.forEach(item => {
console.log();`
});
Response Type:
`typescript
interface Inventory {
items: InventoryItem[];
total_count: number;
}
interface InventoryItem {
id: string;
user_id: string;
item_type: string;
item_id: string;
quantity: number;
metadata?: Record
created_at: string;
updated_at: string;
}
`
#### Get Specific Inventory Item
Fetch details for a single item:
`typescript
const item = await client.getInventoryItem('item-id-123');
console.log(Item: ${item.item_type});Quantity: ${item.quantity}
console.log();`
if (item.metadata) {
console.log('Metadata:', item.metadata);
}
API Endpoints:
- GET /api/v1/inventory - Get all inventory itemsGET /api/v1/inventory/:id
- - Get specific item
The SDK includes support for Google H5 Games Ads. Ads are disabled by default and must be explicitly enabled in the configuration.
`typescript
import { HyveClient } from "@hyve-sdk/js";
// Enable ads in initial config
const client = new HyveClient({
ads: {
enabled: true, // Must be set to true
sound: 'on',
debug: true,
onBeforeAd: (type) => {
console.log('Pausing game for ad:', type);
game.pause();
},
onAfterAd: (type) => {
console.log('Resuming game after ad');
game.resume();
},
onRewardEarned: () => {
console.log('User earned reward!');
player.coins += 100;
}
}
});
// Show different ad types
const result = await client.showAd('rewarded');
if (result.success) {
console.log('User watched the ad!');
}
await client.showAd('interstitial'); // Between levels
await client.showAd('preroll'); // Game start
`
Add the Google H5 Games Ads SDK to your HTML:
`html`
| Type | Use Case |
|------|----------|
| rewarded | User watches full ad for reward (coins, lives, etc.) |interstitial
| | Between levels or game screens |preroll
| | Before game starts |
`typescript`
interface AdConfig {
enabled?: boolean; // Enable/disable ads (default: false)
sound?: 'on' | 'off'; // Sound setting (default: 'on')
debug?: boolean; // Enable debug logging (default: false)
onBeforeAd?: (type) => void; // Called before ad shows
onAfterAd?: (type) => void; // Called after ad finishes
onRewardEarned?: () => void; // Called when user earns reward
}
`typescript
// Configure ads after initialization
client.configureAds({ enabled: true, sound: 'off' });
// Show an ad
const result = await client.showAd('rewarded');
// Check status
client.areAdsEnabled(); // Boolean
client.areAdsReady(); // Boolean
`
See docs/ads.md for detailed documentation and examples.
Requirements:
- JWT token must be available (via hyve-access URL parameter)
- User must be authenticated
The SDK includes unified billing support for both web (Stripe) and native (In-App Purchases) platforms. Billing automatically detects the platform and routes to the appropriate payment method.
`typescript
import { HyveClient } from "@hyve-sdk/js";
// Enable billing in initial config
const client = new HyveClient({
billing: {
stripePublishableKey: 'pk_test_...',
checkoutUrl: 'https://your-api.com',
}
});
// Authenticate user
await client.authenticateFromUrl(window.location.search);
// Initialize billing (uses client's userId and gameId automatically)
const initialized = await client.initializeBilling();
if (initialized && client.isBillingAvailable()) {
// Set up purchase callbacks
client.onPurchaseComplete((result) => {
console.log('Purchase successful!', result.transactionId);
// Refresh inventory
client.getInventory().then(inv => console.log('Updated inventory:', inv));
});
client.onPurchaseError((result) => {
console.error('Purchase failed:', result.error?.message);
});
// Get available products
const products = await client.getBillingProducts();
console.log('Available products:', products);
// Purchase a product
await client.purchaseProduct('price_1234', {
elementId: 'stripe-checkout-element' // For web platform
});
}
`
The SDK automatically detects the platform and uses the appropriate billing method:
| Platform | Payment Method | Requirements |
|----------|---------------|--------------|
| Web | Stripe Embedded Checkout | Stripe publishable key |
| Native (iOS/Android) | In-App Purchases | Native app integration |
For web platform, add a container element for Stripe checkout:
`html`
Stripe.js will be loaded automatically by the SDK.
For native platform, ensure the mobile app implements the Native Bridge billing messages.
`typescript`
interface BillingConfig {
stripePublishableKey?: string; // Stripe key for web (required for web)
checkoutUrl?: string; // API endpoint for checkout
gameId?: number; // Game identifier
userId?: string; // User identifier
}
Note: When using billing through HyveClient, userId and gameId are automatically populated from the authenticated user.
`typescript
// Configure billing after initialization
client.configureBilling({
stripePublishableKey: 'pk_live_...',
checkoutUrl: 'https://api.example.com'
});
// Initialize billing
await client.initializeBilling();
// Check platform and availability
const platform = client.getBillingPlatform(); // 'web' | 'native' | 'unknown'
const available = client.isBillingAvailable(); // Boolean
// Get products
const products = await client.getBillingProducts();
// Purchase a product
const result = await client.purchaseProduct(productId, {
elementId: 'stripe-checkout-element' // Optional, defaults to 'stripe-checkout-element'
});
// Set up callbacks
client.onPurchaseComplete((result) => {
console.log('Success!', result);
});
client.onPurchaseError((result) => {
console.error('Failed:', result.error);
});
// Optional: Listen to billing logs
client.onBillingLog((level, message, data) => {
console.log([${level}] ${message}, data);
});
// Clean up checkout UI
client.unmountBillingCheckout();
`
`typescript`
interface BillingProduct {
productId: string; // Product/price ID
title: string; // Product name
description: string; // Product description
price: number; // Price in dollars (e.g., 9.99)
localizedPrice: string; // Formatted price (e.g., "$9.99")
currency: string; // Currency code (e.g., "USD")
}
`typescript`
interface PurchaseResult {
success: boolean;
productId: string;
transactionId?: string;
transactionDate?: string;
error?: {
code: string;
message: string;
};
}
`typescript
const client = new HyveClient({
billing: {
stripePublishableKey: process.env.VITE_STRIPE_KEY,
checkoutUrl: process.env.VITE_CHECKOUT_URL,
}
});
// Authenticate
await client.authenticateFromUrl();
// Initialize billing
await client.initializeBilling();
// Set up callbacks with telemetry
client.onPurchaseComplete((result) => {
// Send success telemetry
client.sendTelemetry(
'shop',
'purchase',
'complete',
'success',
null,
{ productId: result.productId, transactionId: result.transactionId }
);
// Refresh inventory
client.getInventory();
});
client.onPurchaseError((result) => {
// Send error telemetry
client.sendTelemetry(
'shop',
'purchase',
'error',
'failed',
null,
{
productId: result.productId,
errorCode: result.error?.code,
errorMessage: result.error?.message
}
);
});
// Get and display products
const products = await client.getBillingProducts();
`
See docs/examples/billing-with-client-example.ts for detailed examples including React components and Phaser integration.
Requirements:
- JWT token must be available (via hyve-access URL parameter)game-id
- User must be authenticated
- Game ID must be available (via URL parameter or JWT)
- For web: Stripe publishable key required
- For native: Mobile app must implement Native Bridge billing integration
Provides type-safe bidirectional communication between your web application and the React Native mobile app.
`typescript
import { NativeBridge, NativeMessageType } from "@hyve-sdk/js";
// Initialize on app start
if (NativeBridge.isNativeContext()) {
NativeBridge.initialize();
}
`
Request information about In-App Purchase availability:
`typescript
// Register response handler
NativeBridge.on("IAP_AVAILABILITY_RESULT", (payload) => {
if (payload.available) {
console.log("IAP is available on this device");
// Show purchase UI
} else {
console.log("IAP is not available");
// Hide purchase features
}
});
// Send request
NativeBridge.checkIAPAvailability();
`
Request notification permissions from the native app:
`typescript
// Register response handlers
NativeBridge.on("PUSH_PERMISSION_GRANTED", (payload) => {
console.log("Push notifications enabled");
console.log("Token:", payload?.token);
});
NativeBridge.on("PUSH_PERMISSION_DENIED", () => {
console.log("Push notifications disabled");
});
// Send request
NativeBridge.requestNotificationPermission();
`
Send custom messages to the native app:
`typescript
// Send message with payload
NativeBridge.send("CUSTOM_EVENT", {
action: "open_settings",
data: { setting: "notifications" }
});
// Listen for custom responses
NativeBridge.on("CUSTOM_RESPONSE", (payload) => {
console.log("Received:", payload);
});
`
Web → Native:
- CHECK_IAP_AVAILABILITY - Check if IAP is availableREQUEST_NOTIFICATION_PERMISSION
- - Request push notification permission
Native → Web:
- IAP_AVAILABILITY_RESULT - Response with IAP availabilityPUSH_PERMISSION_GRANTED
- - Push permission grantedPUSH_PERMISSION_DENIED
- - Push permission denied
- NativeBridge.isNativeContext() - Check if running in React Native WebViewNativeBridge.initialize()
- - Initialize message listenerNativeBridge.send(type, payload?)
- - Send message to nativeNativeBridge.on(type, handler)
- - Register message handlerNativeBridge.off(type)
- - Unregister message handlerNativeBridge.clearHandlers()
- - Clear all handlersNativeBridge.checkIAPAvailability()
- - Helper for IAP checkNativeBridge.requestNotificationPermission()
- - Helper for notification permission
For complete documentation, see docs/NATIVE_BRIDGE.md.
The SDK includes a built-in logger that's automatically enabled in development environments.
`typescript
import { logger } from "@hyve-sdk/js";
logger.debug("Debug information", { data: "value" });
logger.info("Informational message");
logger.warn("Warning message");
logger.error("Error message", error);
`
Automatic Behavior:
- Development (NODE_ENV !== 'production'): Logging enabled by defaultNODE_ENV === 'production'
- Production (): Logging disabled by default
Browser Override:
`javascript`
// Enable specific log levels
localStorage.setItem('HYVE_SDK_LOG_LEVEL', 'error,warn');
Node.js Override:
`bash`
HYVE_SDK_LOG_LEVEL=error,warn node app.js
Programmatic Control:
`typescript
import { Logger } from "@hyve-sdk/js";
const logger = new Logger();
logger.setLevels(['error', 'warn']);
`
Create namespaced loggers for different parts of your application:
`typescript
import { logger } from "@hyve-sdk/js";
const gameLogger = logger.child('Game');
gameLogger.info('Game started');
// Output: [Hyve SDK] [Game] [INFO] [timestamp] Game started
const uiLogger = logger.child('UI');
uiLogger.debug('Button clicked');
// Output: [Hyve SDK] [UI] [DEBUG] [timestamp] Button clicked
`
- Automatic environment detection: Enables/disables based on NODE_ENV
- Configurable log levels: debug, info, warn, error
- Timestamps: All logs include ISO 8601 timestamps
- Prefixed output: All logs prefixed with [Hyve SDK]
- Child loggers: Create namespaced loggers for different modules
- Browser storage: Log level persists in localStorage
- Authenticate from URL parameters (extracts JWT, game ID, user auth)
- getUserId() - Get authenticated user ID (address)
- getSessionId() - Get unique session ID
- getGameId() - Get game ID from URL parameters
- isUserAuthenticated() - Check if user is authenticated
- hasJwtToken() - Check if JWT token is available
- getJwtToken() - Get JWT token string
- logout() - Clear user authentication
- reset() - Reset client state with new session$3
- callApi - Generic authenticated API call
- getInventory() - Get user's inventory
- getInventoryItem(itemId) - Get specific inventory item$3
- sendTelemetry(location, category, action, subCategory?, subAction?, details?, platformId?) - Send JWT-authenticated analytics event (uses game ID from URL)
- updateTelemetryConfig(config) - Update telemetry settings$3
- configureAds(config) - Configure ads service
- showAd(type) - Show an ad ('rewarded', 'interstitial', or 'preroll')
- areAdsEnabled() - Check if ads are enabled
- areAdsReady() - Check if ads are ready to show$3
- getApiBaseUrl() - Get current API base URL
- updateTelemetryConfig(config) - Update client configurationAuthentication Flow
$3
1. User authenticates on platform
2. Platform generates hyve-token: signature.address.random.timestamp
3. Token passed via URL parameter hyve-token
4. SDK verifies token with verifyHyveToken() or verifyAuthentication()$3
1. User signs message containing metadata (expiration, address)
2. Signature and message passed via URL parameters
3. SDK verifies with handleVerifyMessage() or verifyAuthentication()Security Considerations
- Token Expiration: Modern tokens expire after 10 minutes by default
- Domain Validation: Always validate origin domains in production
- Signature Verification: All signatures verified using ethers.js
- Localhost Exception: localhost always allowed for development
TypeScript Support
Full TypeScript support with exported types for all utilities and return values.
Dependencies
- ethers: ^6.13.7 - Ethereum signature verification
- uuid: (peer dependency) - UUID generation
Build Configuration
The SDK builds to multiple formats:
- CommonJS (
dist/index.js)
- ES Modules (dist/index.mjs)
- TypeScript declarations (dist/index.d.ts)Development
`bash
Install dependencies
bun installType checking
bun run check-typesLinting
bun run lintBuild
bun run build
``For complete documentation and examples, visit https://docs.hyve.gg
- Telemetry Guide - Best practices, validation rules, and examples for event tracking
- Billing Integration - Platform-aware billing with Stripe and In-App Purchases
- Billing Migration Guide - Upgrading from older billing implementations
- Ads Integration - Google H5 Games Ads integration
- Native Bridge - React Native WebView communication
MIT