@hyve-sdk/js 1.5.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,862 +1,388 @@
1
1
  # @hyve-sdk/js
2
2
 
3
- TypeScript SDK for web3 authentication and game integration, providing secure signature verification and utility functions.
3
+ TypeScript SDK for integrating games with the Hyve platform. Provides authentication, telemetry, persistent storage, ads, billing, and native bridge capabilities.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- bun add @hyve-sdk/js
9
- # or
10
- npm install @hyve-sdk/js
11
- # or
12
8
  pnpm add @hyve-sdk/js
13
9
  ```
14
10
 
15
- ## Features
11
+ ## Quick Start
16
12
 
17
- - **Web3 Authentication**: EVM signature validation and verification
18
- - **Modern & Legacy Token Support**: Dual authentication token formats
19
- - **JWT Authentication**: Support for JWT tokens passed via URL parameters
20
- - **API Integration**: Authenticated API calls with JWT token support
21
- - **Inventory Management**: Built-in methods for user inventory operations
22
- - **Telemetry Tracking**: Session-based analytics and event tracking
23
- - **Billing Integration**: Unified billing for web (Stripe) and native (In-App Purchases) platforms
24
- - **Ads Integration**: Google H5 Games Ads support (disabled by default)
25
- - **Native Bridge**: Type-safe communication with React Native WebView apps
26
- - **Logger**: Environment-aware logging system with configurable log levels
27
- - **Security Utilities**: Domain validation and referrer checking
28
- - **URL Parameter Parsing**: Easy extraction of authentication parameters
29
- - **UUID Generation**: Built-in UUID v4 generation
30
-
31
- ## Core Components
32
-
33
- ### HyveClient
34
- Main client class for SDK operations including authentication, telemetry, and API calls.
35
-
36
- ```typescript
13
+ ```ts
37
14
  import { HyveClient } from "@hyve-sdk/js";
38
15
 
39
- // Initialize client
40
- // Environment (dev/prod) is automatically detected from the parent page URL
16
+ // Authentication is automatic — the SDK reads hyve-access and game-id from the URL
41
17
  const client = new HyveClient();
42
18
 
43
- // Authenticate from URL parameters
44
- // Extracts: hyve-token/signature, hyve-access (JWT), game-id
45
- const authenticated = await client.authenticateFromUrl();
46
- if (authenticated) {
47
- console.log('User ID:', client.getUserId());
48
- console.log('Session ID:', client.getSessionId());
49
- console.log('Has JWT:', client.hasJwtToken());
50
- console.log('Game ID:', client.getGameId());
51
- }
19
+ console.log("User ID:", client.getUserId());
20
+ console.log("Game ID:", client.getGameId());
21
+ console.log("Authenticated:", client.isUserAuthenticated());
52
22
  ```
53
23
 
54
- **Environment Detection:**
55
- The SDK automatically detects whether to use dev or prod environment by checking the parent page URL:
56
- - **Dev**: `marvin.dev.hyve.gg` or `dev.hyve.gg`
57
- - **Prod**: `marvin.hyve.gg` or `hyve.gg`
24
+ The SDK reads authentication from URL parameters automatically during construction:
58
25
 
59
- You can optionally override this for testing:
60
- ```typescript
61
- // Only use for local testing - NOT for production code
62
- const client = new HyveClient({
63
- isDev: true, // Force dev mode for testing
64
- apiBaseUrl: 'https://...' // Optional custom API URL
65
- });
66
26
  ```
67
-
68
- ### Authentication Utilities
69
-
70
- #### Parse URL Parameters
71
- Extract authentication and game parameters from URL:
72
-
73
- ```typescript
74
- import { parseUrlParams } from "@hyve-sdk/js";
75
-
76
- const params = parseUrlParams(window.location.search);
77
- // Returns:
78
- // {
79
- // signature: string,
80
- // message: string,
81
- // gameStartTab: string,
82
- // hyveToken: string,
83
- // platform: string,
84
- // hyveAccess: string, // JWT token
85
- // gameId: string // Game identifier
86
- // }
27
+ https://your-game.com?hyve-access=eyJhbGci...&game-id=my-game
87
28
  ```
88
29
 
89
- #### Verify Authentication
90
- Unified verification supporting both modern and legacy tokens:
91
-
92
- ```typescript
93
- import { verifyAuthentication } from "@hyve-sdk/js";
94
-
95
- const result = verifyAuthentication({
96
- hyveToken: params.hyveToken, // Modern token format
97
- signature: params.signature, // Legacy format
98
- message: params.message // Legacy format
99
- });
30
+ **Environment detection** happens automatically from the parent page URL (games run in iframes):
31
+ - Dev: `marvin.dev.hyve.gg` or `dev.hyve.gg`
32
+ - Prod: `marvin.hyve.gg` or `hyve.gg`
33
+ - Override with `isDev` in config for local testing only
100
34
 
101
- if (result.isValid) {
102
- console.log('Authenticated address:', result.address);
103
- console.log('Auth method used:', result.method); // 'modern' or 'legacy'
104
- }
105
- ```
35
+ ## React Integration
106
36
 
107
- #### Modern Token Verification (Hyve Token)
108
- Verify modern authentication tokens with expiration:
37
+ Import from `@hyve-sdk/js/react` for the React provider and hook:
109
38
 
110
- ```typescript
111
- import { verifyHyveToken } from "@hyve-sdk/js";
39
+ ```tsx
40
+ import { HyveSdkProvider, useHyveSdk } from "@hyve-sdk/js/react";
112
41
 
113
- // Token format: signature.address.randomBase64.timestamp
114
- const address = verifyHyveToken(hyveToken, 600); // 600 seconds max age
115
- if (address) {
116
- console.log('Valid token for address:', address);
42
+ function App() {
43
+ return (
44
+ <HyveSdkProvider config={{ isDev: true }}>
45
+ <Game />
46
+ </HyveSdkProvider>
47
+ );
117
48
  }
118
- ```
119
-
120
- #### Legacy Token Verification
121
- Verify legacy signed messages with metadata:
122
-
123
- ```typescript
124
- import { handleVerifyMessage, validateSignature } from "@hyve-sdk/js";
125
-
126
- // Method 1: Verify message with embedded metadata
127
- const address = handleVerifyMessage(signature, message);
128
-
129
- // Method 2: Simple signature validation
130
- const isValid = validateSignature(signature, message, userId);
131
- ```
132
-
133
- ### Security Utilities
134
-
135
- #### Domain Validation
136
- Check if current domain is allowed:
137
49
 
138
- ```typescript
139
- import { isDomainAllowed } from "@hyve-sdk/js";
50
+ function Game() {
51
+ const sdk = useHyveSdk();
140
52
 
141
- // Single domain
142
- const allowed = isDomainAllowed('example.com', window.location.hostname);
143
-
144
- // Multiple domains with wildcard support
145
- const allowed = isDomainAllowed(
146
- ['example.com', '*.subdomain.com'],
147
- window.location.hostname
148
- );
53
+ const handleScore = () => {
54
+ sdk.sendTelemetry("game", "player", "score_submitted", null, null, { score: 1000 });
55
+ };
149
56
 
150
- // Note: localhost is always allowed
57
+ return <button onClick={handleScore}>Submit Score</button>;
58
+ }
151
59
  ```
152
60
 
153
- ### Utility Functions
154
-
155
- #### UUID Generation
156
- Generate random UUID v4:
61
+ You can also pass a pre-created client:
157
62
 
158
- ```typescript
159
- import { generateUUID } from "@hyve-sdk/js";
63
+ ```tsx
64
+ const client = new HyveClient({ isDev: true });
160
65
 
161
- const id = generateUUID();
66
+ <HyveSdkProvider client={client}>
67
+ <App />
68
+ </HyveSdkProvider>
162
69
  ```
163
70
 
164
- ## Telemetry & Analytics
165
-
166
- ### Send Telemetry Events
167
- Track user actions and game events using JWT authentication:
71
+ ## Telemetry
168
72
 
169
- ```typescript
170
- // Send a user-level telemetry event
171
- // Game ID is automatically extracted from 'game-id' URL parameter
73
+ ```ts
172
74
  await client.sendTelemetry(
173
- 'game', // Event location
174
- 'player', // Event category
175
- 'action', // Event action
176
- 'combat', // Event sub-category (optional)
177
- 'attack', // Event sub-action (optional)
178
- { // Event details - auto-stringified (optional)
179
- button: 'attack-btn',
180
- screenPosition: { x: 100, y: 200 },
75
+ "game", // location
76
+ "player", // category
77
+ "action", // action
78
+ "combat", // sub-category (optional)
79
+ "attack", // sub-action (optional)
80
+ { // event details (optional)
181
81
  damage: 100,
182
- targetId: 'enemy-123',
183
- weaponType: 'sword',
184
- level: 3
185
- },
186
- 'web-chrome' // Platform ID (optional)
82
+ targetId: "enemy-123",
83
+ }
187
84
  );
188
85
  ```
189
86
 
190
- **Requirements:**
191
- - Requires JWT token (from `hyve-access` URL parameter)
192
- - Requires authenticated user
193
- - Requires game ID (from `game-id` URL parameter)
194
- - User ID is automatically extracted from JWT (cannot be spoofed)
87
+ Requires a valid `hyve-access` JWT and `game-id` in the URL.
195
88
 
196
- **URL Parameters Expected:**
197
- - `hyve-access` - JWT authentication token
198
- - `game-id` - Game identifier (associates all telemetry with this game)
199
- - `hyve-token` or `signature`+`message` - For user authentication
89
+ ## Persistent Game Data
200
90
 
201
- **Features:**
202
- - Automatically includes `session_id` and `game_id` from client
203
- - Objects in `event_details` are auto-stringified to JSON
204
- - Validates `event_details` is valid JSON before sending (returns false if invalid)
205
- - All events tied to authenticated user identity
91
+ Save and retrieve game data with either cloud (default) or local storage:
206
92
 
207
- ## API Integration
93
+ ```ts
94
+ // Save a value
95
+ await client.saveGameData("player_level", 5);
96
+ await client.saveGameData("settings", { volume: 0.8, fullscreen: true });
208
97
 
209
- ### JWT Authentication
210
- The SDK supports JWT tokens and game IDs passed via URL parameters:
98
+ // Get a value
99
+ const item = await client.getGameData("player_level");
100
+ console.log(item?.value); // 5
211
101
 
212
- ```typescript
213
- // URL: https://game.com?hyve-access=your-jwt-token&game-id=my-game
102
+ // Batch save
103
+ await client.batchSaveGameData([
104
+ { key: "coins", value: 1200 },
105
+ { key: "lives", value: 3 },
106
+ ]);
214
107
 
215
- // Authenticate extracts JWT and game ID automatically
216
- await client.authenticateFromUrl();
108
+ // Batch get
109
+ const items = await client.getMultipleGameData(["coins", "lives"]);
217
110
 
218
- // Check availability
219
- if (client.hasJwtToken()) {
220
- console.log('JWT token:', client.getJwtToken());
221
- console.log('Game ID:', client.getGameId());
222
- }
111
+ // Delete
112
+ await client.deleteGameData("temp_key");
113
+ await client.deleteMultipleGameData(["key1", "key2"]);
223
114
  ```
224
115
 
225
- ### Generic API Calls
226
- Make authenticated API requests:
227
-
228
- ```typescript
229
- // GET request
230
- const userData = await client.callApi('/api/v1/user');
231
-
232
- // POST request with body
233
- const result = await client.callApi('/api/v1/game/score', {
234
- method: 'POST',
235
- body: JSON.stringify({ score: 1000 })
236
- });
237
-
238
- // With TypeScript typing
239
- interface UserData {
240
- id: string;
241
- username: string;
242
- }
243
- const user = await client.callApi<UserData>('/api/v1/user');
244
- ```
245
-
246
- ### Inventory Management
247
-
248
- #### Get User Inventory
249
- Retrieve all inventory items:
250
-
251
- ```typescript
252
- const inventory = await client.getInventory();
253
-
254
- console.log(`Total items: ${inventory.total_count}`);
255
- inventory.items.forEach(item => {
256
- console.log(`${item.item_type}: ${item.quantity}x`);
257
- });
258
- ```
259
-
260
- **Response Type:**
261
- ```typescript
262
- interface Inventory {
263
- items: InventoryItem[];
264
- total_count: number;
265
- }
266
-
267
- interface InventoryItem {
268
- id: string;
269
- user_id: string;
270
- item_type: string;
271
- item_id: string;
272
- quantity: number;
273
- metadata?: Record<string, any>;
274
- created_at: string;
275
- updated_at: string;
276
- }
277
- ```
116
+ ### Storage Modes
278
117
 
279
- #### Get Specific Inventory Item
280
- Fetch details for a single item:
118
+ ```ts
119
+ // Set mode at construction
120
+ const client = new HyveClient({ storageMode: "local" });
281
121
 
282
- ```typescript
283
- const item = await client.getInventoryItem('item-id-123');
122
+ // Or override per-call
123
+ await client.saveGameData("key", "value", "local");
124
+ await client.getGameData("key", "cloud");
284
125
 
285
- console.log(`Item: ${item.item_type}`);
286
- console.log(`Quantity: ${item.quantity}`);
287
- if (item.metadata) {
288
- console.log('Metadata:', item.metadata);
289
- }
126
+ // Change mode at runtime
127
+ client.configureStorage("cloud");
128
+ console.log(client.getStorageMode()); // "cloud"
290
129
  ```
291
130
 
292
- **API Endpoints:**
293
- - `GET /api/v1/inventory` - Get all inventory items
294
- - `GET /api/v1/inventory/:id` - Get specific item
295
-
296
- ## Ads Integration
297
-
298
- The SDK includes support for Google H5 Games Ads. **Ads are disabled by default** and must be explicitly enabled in the configuration.
131
+ | Mode | Description |
132
+ |------|-------------|
133
+ | `cloud` | Synced to backend API (default) |
134
+ | `local` | Browser `localStorage`, device-only |
299
135
 
300
- ### Quick Start
136
+ ## Ads
301
137
 
302
- ```typescript
303
- import { HyveClient } from "@hyve-sdk/js";
138
+ Ads are disabled by default and must be explicitly configured.
304
139
 
305
- // Enable ads in initial config
140
+ ```ts
306
141
  const client = new HyveClient({
307
142
  ads: {
308
- enabled: true, // Must be set to true
309
- sound: 'on',
310
- debug: true,
311
- onBeforeAd: (type) => {
312
- console.log('Pausing game for ad:', type);
313
- game.pause();
314
- },
315
- onAfterAd: (type) => {
316
- console.log('Resuming game after ad');
317
- game.resume();
318
- },
319
- onRewardEarned: () => {
320
- console.log('User earned reward!');
321
- player.coins += 100;
322
- }
323
- }
143
+ enabled: true,
144
+ onBeforeAd: (type) => game.pause(),
145
+ onAfterAd: (type) => game.resume(),
146
+ onRewardEarned: () => { player.coins += 100; },
147
+ },
324
148
  });
325
149
 
326
- // Show different ad types
327
- const result = await client.showAd('rewarded');
150
+ const result = await client.showAd("rewarded");
328
151
  if (result.success) {
329
- console.log('User watched the ad!');
152
+ console.log("User watched the ad");
330
153
  }
331
154
 
332
- await client.showAd('interstitial'); // Between levels
333
- await client.showAd('preroll'); // Game start
155
+ await client.showAd("interstitial"); // between levels
156
+ await client.showAd("preroll"); // game start
334
157
  ```
335
158
 
336
- ### Prerequisites
337
-
338
- Add the Google H5 Games Ads SDK to your HTML:
159
+ | Ad Type | Use Case |
160
+ |---------|----------|
161
+ | `rewarded` | User watches full ad for a reward |
162
+ | `interstitial` | Between levels or game screens |
163
+ | `preroll` | Before the game starts |
339
164
 
340
- ```html
341
- <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
342
- <script>
343
- window.adBreak = window.adBreak || function(o) {
344
- (window.adsbygoogle = window.adsbygoogle || []).push(o);
345
- };
346
- window.adConfig = window.adConfig || function(o) {
347
- (window.adsbygoogle = window.adsbygoogle || []).push(o);
348
- };
349
- </script>
350
- ```
165
+ The SDK automatically routes ad calls through the appropriate platform SDK (CrazyGames, Playgama, or the default Google H5 Ads SDK) based on the current domain.
351
166
 
352
- ### Ad Types
167
+ ## Platform Integrations
353
168
 
354
- | Type | Use Case |
355
- |------|----------|
356
- | `rewarded` | User watches full ad for reward (coins, lives, etc.) |
357
- | `interstitial` | Between levels or game screens |
358
- | `preroll` | Before game starts |
359
-
360
- ### Configuration
361
-
362
- ```typescript
363
- interface AdConfig {
364
- enabled?: boolean; // Enable/disable ads (default: false)
365
- sound?: 'on' | 'off'; // Sound setting (default: 'on')
366
- debug?: boolean; // Enable debug logging (default: false)
367
- onBeforeAd?: (type) => void; // Called before ad shows
368
- onAfterAd?: (type) => void; // Called after ad finishes
369
- onRewardEarned?: () => void; // Called when user earns reward
370
- }
371
- ```
169
+ ### CrazyGames
372
170
 
373
- ### Methods
171
+ When running on CrazyGames, the SDK auto-initializes the CrazyGames SDK and routes ads through it. Use these additional lifecycle methods:
374
172
 
375
- ```typescript
376
- // Configure ads after initialization
377
- client.configureAds({ enabled: true, sound: 'off' });
173
+ ```ts
174
+ // Call when gameplay begins (required by CrazyGames policy)
175
+ await client.gameplayStart();
378
176
 
379
- // Show an ad
380
- const result = await client.showAd('rewarded');
177
+ // Call when gameplay stops (paused, died, menu, etc.)
178
+ await client.gameplayStop();
381
179
 
382
- // Check status
383
- client.areAdsEnabled(); // Boolean
384
- client.areAdsReady(); // Boolean
180
+ // Trigger a celebration effect on the CrazyGames website
181
+ await client.happytime();
385
182
  ```
386
183
 
387
- See [docs/ads.md](./docs/ads.md) for detailed documentation and examples.
388
-
389
- **Requirements:**
390
- - JWT token must be available (via `hyve-access` URL parameter)
391
- - User must be authenticated
392
-
393
- ## Billing Integration
184
+ ### Playgama
394
185
 
395
- 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.
186
+ When running on Playgama, the SDK auto-initializes the Playgama Bridge and routes ads through it. No additional setup required.
396
187
 
397
- ### Quick Start
188
+ ## Billing
398
189
 
399
- ```typescript
400
- import { HyveClient } from "@hyve-sdk/js";
190
+ Billing supports web (Stripe) and native (In-App Purchases) — platform is detected automatically.
401
191
 
402
- // Enable billing in initial config
192
+ ```ts
403
193
  const client = new HyveClient({
404
194
  billing: {
405
- stripePublishableKey: 'pk_test_...',
406
- checkoutUrl: 'https://your-api.com',
407
- }
195
+ stripePublishableKey: "pk_live_...",
196
+ },
408
197
  });
409
198
 
410
- // Authenticate user
411
- await client.authenticateFromUrl(window.location.search);
412
-
413
- // Initialize billing (uses client's userId and gameId automatically)
414
- const initialized = await client.initializeBilling();
415
-
416
- if (initialized && client.isBillingAvailable()) {
417
- // Set up purchase callbacks
199
+ if (client.isBillingAvailable()) {
418
200
  client.onPurchaseComplete((result) => {
419
- console.log('Purchase successful!', result.transactionId);
420
- // Refresh inventory
421
- client.getInventory().then(inv => console.log('Updated inventory:', inv));
201
+ console.log("Purchase successful:", result.transactionId);
422
202
  });
423
203
 
424
204
  client.onPurchaseError((result) => {
425
- console.error('Purchase failed:', result.error?.message);
205
+ console.error("Purchase failed:", result.error?.message);
426
206
  });
427
207
 
428
- // Get available products
429
208
  const products = await client.getBillingProducts();
430
- console.log('Available products:', products);
431
-
432
- // Purchase a product
433
- await client.purchaseProduct('price_1234', {
434
- elementId: 'stripe-checkout-element' // For web platform
435
- });
209
+ await client.purchaseProduct("price_1234");
436
210
  }
437
211
  ```
438
212
 
439
- ### Platform Support
440
-
441
- The SDK automatically detects the platform and uses the appropriate billing method:
442
-
443
- | Platform | Payment Method | Requirements |
444
- |----------|---------------|--------------|
445
- | Web | Stripe Embedded Checkout | Stripe publishable key |
446
- | Native (iOS/Android) | In-App Purchases | Native app integration |
447
-
448
- ### Prerequisites
449
-
450
- For web platform, add a container element for Stripe checkout:
213
+ For web, add a container element for the Stripe checkout UI:
451
214
 
452
215
  ```html
453
216
  <div id="stripe-checkout-element"></div>
454
217
  ```
455
218
 
456
- Stripe.js will be loaded automatically by the SDK.
457
-
458
- For native platform, ensure the mobile app implements the Native Bridge billing messages.
459
-
460
- ### Configuration
461
-
462
- ```typescript
463
- interface BillingConfig {
464
- stripePublishableKey?: string; // Stripe key for web (required for web)
465
- checkoutUrl?: string; // API endpoint for checkout
466
- gameId?: number; // Game identifier
467
- userId?: string; // User identifier
468
- }
469
- ```
470
-
471
- Note: When using billing through HyveClient, `userId` and `gameId` are automatically populated from the authenticated user.
472
-
473
- ### Methods
474
-
475
- ```typescript
476
- // Configure billing after initialization
477
- client.configureBilling({
478
- stripePublishableKey: 'pk_live_...',
479
- checkoutUrl: 'https://api.example.com'
480
- });
481
-
482
- // Initialize billing
483
- await client.initializeBilling();
484
-
485
- // Check platform and availability
486
- const platform = client.getBillingPlatform(); // 'web' | 'native' | 'unknown'
487
- const available = client.isBillingAvailable(); // Boolean
488
-
489
- // Get products
490
- const products = await client.getBillingProducts();
491
-
492
- // Purchase a product
493
- const result = await client.purchaseProduct(productId, {
494
- elementId: 'stripe-checkout-element' // Optional, defaults to 'stripe-checkout-element'
495
- });
496
-
497
- // Set up callbacks
498
- client.onPurchaseComplete((result) => {
499
- console.log('Success!', result);
500
- });
501
-
502
- client.onPurchaseError((result) => {
503
- console.error('Failed:', result.error);
504
- });
505
-
506
- // Optional: Listen to billing logs
507
- client.onBillingLog((level, message, data) => {
508
- console.log(`[${level}] ${message}`, data);
509
- });
510
-
511
- // Clean up checkout UI
512
- client.unmountBillingCheckout();
513
- ```
514
-
515
- ### Product Interface
516
-
517
- ```typescript
518
- interface BillingProduct {
519
- productId: string; // Product/price ID
520
- title: string; // Product name
521
- description: string; // Product description
522
- price: number; // Price in dollars (e.g., 9.99)
523
- localizedPrice: string; // Formatted price (e.g., "$9.99")
524
- currency: string; // Currency code (e.g., "USD")
525
- }
526
- ```
527
-
528
- ### Purchase Result
529
-
530
- ```typescript
531
- interface PurchaseResult {
532
- success: boolean;
533
- productId: string;
534
- transactionId?: string;
535
- transactionDate?: string;
536
- error?: {
537
- code: string;
538
- message: string;
539
- };
540
- }
541
- ```
542
-
543
- ### Complete Example with Telemetry
544
-
545
- ```typescript
546
- const client = new HyveClient({
547
- billing: {
548
- stripePublishableKey: process.env.VITE_STRIPE_KEY,
549
- checkoutUrl: process.env.VITE_CHECKOUT_URL,
550
- }
551
- });
219
+ | Platform | Payment Method | Detection |
220
+ |----------|---------------|-----------|
221
+ | Web | Stripe Embedded Checkout | Default |
222
+ | Native iOS/Android | In-App Purchases | `ReactNativeWebView` in window |
552
223
 
553
- // Authenticate
554
- await client.authenticateFromUrl();
555
-
556
- // Initialize billing
557
- await client.initializeBilling();
558
-
559
- // Set up callbacks with telemetry
560
- client.onPurchaseComplete((result) => {
561
- // Send success telemetry
562
- client.sendTelemetry(
563
- 'shop',
564
- 'purchase',
565
- 'complete',
566
- 'success',
567
- null,
568
- { productId: result.productId, transactionId: result.transactionId }
569
- );
224
+ ## Native Bridge
570
225
 
571
- // Refresh inventory
572
- client.getInventory();
573
- });
226
+ Type-safe bidirectional communication between your web game and a React Native WebView host.
574
227
 
575
- client.onPurchaseError((result) => {
576
- // Send error telemetry
577
- client.sendTelemetry(
578
- 'shop',
579
- 'purchase',
580
- 'error',
581
- 'failed',
582
- null,
583
- {
584
- productId: result.productId,
585
- errorCode: result.error?.code,
586
- errorMessage: result.error?.message
587
- }
588
- );
589
- });
228
+ ```ts
229
+ import { NativeBridge } from "@hyve-sdk/js";
590
230
 
591
- // Get and display products
592
- const products = await client.getBillingProducts();
593
- ```
594
-
595
- See [docs/examples/billing-with-client-example.ts](./docs/examples/billing-with-client-example.ts) for detailed examples including React components and Phaser integration.
596
-
597
- **Requirements:**
598
- - JWT token must be available (via `hyve-access` URL parameter)
599
- - User must be authenticated
600
- - Game ID must be available (via `game-id` URL parameter or JWT)
601
- - For web: Stripe publishable key required
602
- - For native: Mobile app must implement Native Bridge billing integration
603
-
604
- ## Native Bridge (React Native WebView)
605
-
606
- Provides type-safe bidirectional communication between your web application and the React Native mobile app.
607
-
608
- ### Quick Start
609
-
610
- ```typescript
611
- import { NativeBridge, NativeMessageType } from "@hyve-sdk/js";
612
-
613
- // Initialize on app start
614
231
  if (NativeBridge.isNativeContext()) {
615
232
  NativeBridge.initialize();
616
- }
617
- ```
618
-
619
- ### Check IAP Availability
620
-
621
- Request information about In-App Purchase availability:
622
-
623
- ```typescript
624
- // Register response handler
625
- NativeBridge.on("IAP_AVAILABILITY_RESULT", (payload) => {
626
- if (payload.available) {
627
- console.log("IAP is available on this device");
628
- // Show purchase UI
629
- } else {
630
- console.log("IAP is not available");
631
- // Hide purchase features
632
- }
633
- });
634
-
635
- // Send request
636
- NativeBridge.checkIAPAvailability();
637
- ```
638
-
639
- ### Request Push Notifications
640
-
641
- Request notification permissions from the native app:
642
-
643
- ```typescript
644
- // Register response handlers
645
- NativeBridge.on("PUSH_PERMISSION_GRANTED", (payload) => {
646
- console.log("Push notifications enabled");
647
- console.log("Token:", payload?.token);
648
- });
649
-
650
- NativeBridge.on("PUSH_PERMISSION_DENIED", () => {
651
- console.log("Push notifications disabled");
652
- });
653
-
654
- // Send request
655
- NativeBridge.requestNotificationPermission();
656
- ```
657
-
658
- ### Send Custom Messages
659
233
 
660
- Send custom messages to the native app:
234
+ // Listen for IAP availability
235
+ NativeBridge.on("IAP_AVAILABILITY_RESULT", (payload) => {
236
+ if (payload.available) {
237
+ console.log("IAP available on:", payload.platform);
238
+ }
239
+ });
240
+ NativeBridge.checkIAPAvailability();
661
241
 
662
- ```typescript
663
- // Send message with payload
664
- NativeBridge.send("CUSTOM_EVENT", {
665
- action: "open_settings",
666
- data: { setting: "notifications" }
667
- });
242
+ // Request push notification permission
243
+ NativeBridge.on("PUSH_PERMISSION_GRANTED", (payload) => {
244
+ console.log("Token:", payload?.token);
245
+ });
246
+ NativeBridge.requestNotificationPermission();
668
247
 
669
- // Listen for custom responses
670
- NativeBridge.on("CUSTOM_RESPONSE", (payload) => {
671
- console.log("Received:", payload);
672
- });
248
+ // Send/receive custom messages
249
+ NativeBridge.send("GAME_EVENT", { action: "level_complete", level: 3 });
250
+ NativeBridge.on("CUSTOM_RESPONSE", (payload) => {
251
+ console.log("Received:", payload);
252
+ });
253
+ }
673
254
  ```
674
255
 
675
- ### Built-in Message Types
676
-
677
- **Web → Native:**
678
- - `CHECK_IAP_AVAILABILITY` - Check if IAP is available
679
- - `REQUEST_NOTIFICATION_PERMISSION` - Request push notification permission
680
-
681
- **Native → Web:**
682
- - `IAP_AVAILABILITY_RESULT` - Response with IAP availability
683
- - `PUSH_PERMISSION_GRANTED` - Push permission granted
684
- - `PUSH_PERMISSION_DENIED` - Push permission denied
685
-
686
- ### API Reference
256
+ ### NativeBridge API
687
257
 
688
- - `NativeBridge.isNativeContext()` - Check if running in React Native WebView
689
- - `NativeBridge.initialize()` - Initialize message listener
690
- - `NativeBridge.send(type, payload?)` - Send message to native
691
- - `NativeBridge.on(type, handler)` - Register message handler
692
- - `NativeBridge.off(type)` - Unregister message handler
693
- - `NativeBridge.clearHandlers()` - Clear all handlers
694
- - `NativeBridge.checkIAPAvailability()` - Helper for IAP check
695
- - `NativeBridge.requestNotificationPermission()` - Helper for notification permission
696
-
697
- For complete documentation, see [docs/NATIVE_BRIDGE.md](./docs/NATIVE_BRIDGE.md).
258
+ | Method | Description |
259
+ |--------|-------------|
260
+ | `isNativeContext()` | Check if running in React Native WebView |
261
+ | `initialize()` | Start the message listener |
262
+ | `send(type, payload?)` | Send a message to the native app |
263
+ | `on(type, handler)` | Register a message handler |
264
+ | `off(type)` | Remove a message handler |
265
+ | `clearHandlers()` | Remove all handlers |
266
+ | `checkIAPAvailability()` | Request IAP availability from native |
267
+ | `requestNotificationPermission()` | Request push notification permission |
698
268
 
699
269
  ## Logger
700
270
 
701
- The SDK includes a built-in logger that's automatically enabled in development environments.
702
-
703
- ### Quick Start
704
-
705
- ```typescript
271
+ ```ts
706
272
  import { logger } from "@hyve-sdk/js";
707
273
 
708
- logger.debug("Debug information", { data: "value" });
274
+ logger.debug("Debug info", { data: "value" });
709
275
  logger.info("Informational message");
710
276
  logger.warn("Warning message");
711
277
  logger.error("Error message", error);
712
- ```
713
-
714
- ### Configuration
715
-
716
- **Automatic Behavior:**
717
- - **Development** (`NODE_ENV !== 'production'`): Logging enabled by default
718
- - **Production** (`NODE_ENV === 'production'`): Logging disabled by default
719
278
 
720
- **Browser Override:**
721
- ```javascript
722
- // Enable specific log levels
723
- localStorage.setItem('HYVE_SDK_LOG_LEVEL', 'error,warn');
724
- ```
725
-
726
- **Node.js Override:**
727
- ```bash
728
- HYVE_SDK_LOG_LEVEL=error,warn node app.js
279
+ // Namespaced child logger
280
+ const gameLogger = logger.child("Game");
281
+ gameLogger.info("Game started");
282
+ // Output: [Hyve SDK] [Game] [INFO] [timestamp] Game started
729
283
  ```
730
284
 
731
- **Programmatic Control:**
732
- ```typescript
733
- import { Logger } from "@hyve-sdk/js";
285
+ Override log level in the browser:
734
286
 
735
- const logger = new Logger();
736
- logger.setLevels(['error', 'warn']);
287
+ ```js
288
+ localStorage.setItem("HYVE_SDK_LOG_LEVEL", "error,warn");
737
289
  ```
738
290
 
739
- ### Child Loggers
740
-
741
- Create namespaced loggers for different parts of your application:
291
+ ## API Reference
742
292
 
743
- ```typescript
744
- import { logger } from "@hyve-sdk/js";
293
+ ### HyveClient Config
745
294
 
746
- const gameLogger = logger.child('Game');
747
- gameLogger.info('Game started');
748
- // Output: [Hyve SDK] [Game] [INFO] [timestamp] Game started
749
-
750
- const uiLogger = logger.child('UI');
751
- uiLogger.debug('Button clicked');
752
- // Output: [Hyve SDK] [UI] [DEBUG] [timestamp] Button clicked
295
+ ```ts
296
+ new HyveClient(config?: {
297
+ isDev?: boolean; // Override env detection (local testing only)
298
+ apiBaseUrl?: string; // Override API base URL
299
+ storageMode?: "cloud" | "local";
300
+ ads?: AdConfig;
301
+ billing?: BillingConfig;
302
+ })
753
303
  ```
754
304
 
755
- ### Features
756
-
757
- - **Automatic environment detection**: Enables/disables based on NODE_ENV
758
- - **Configurable log levels**: debug, info, warn, error
759
- - **Timestamps**: All logs include ISO 8601 timestamps
760
- - **Prefixed output**: All logs prefixed with `[Hyve SDK]`
761
- - **Child loggers**: Create namespaced loggers for different modules
762
- - **Browser storage**: Log level persists in localStorage
763
-
764
- ## Client Methods Reference
765
-
766
305
  ### Authentication
767
- - `authenticateFromUrl(urlParams?)` - Authenticate from URL parameters (extracts JWT, game ID, user auth)
768
- - `getUserId()` - Get authenticated user ID (address)
769
- - `getSessionId()` - Get unique session ID
770
- - `getGameId()` - Get game ID from URL parameters
771
- - `isUserAuthenticated()` - Check if user is authenticated
772
- - `hasJwtToken()` - Check if JWT token is available
773
- - `getJwtToken()` - Get JWT token string
774
- - `logout()` - Clear user authentication
775
- - `reset()` - Reset client state with new session
776
-
777
- ### API Calls
778
- - `callApi<T>(endpoint, options?)` - Generic authenticated API call
779
- - `getInventory()` - Get user's inventory
780
- - `getInventoryItem(itemId)` - Get specific inventory item
781
-
782
- ### Telemetry
783
- - `sendTelemetry(location, category, action, subCategory?, subAction?, details?, platformId?)` - Send JWT-authenticated analytics event (uses game ID from URL)
784
- - `updateTelemetryConfig(config)` - Update telemetry settings
785
-
786
- ### Ads
787
- - `configureAds(config)` - Configure ads service
788
- - `showAd(type)` - Show an ad ('rewarded', 'interstitial', or 'preroll')
789
- - `areAdsEnabled()` - Check if ads are enabled
790
- - `areAdsReady()` - Check if ads are ready to show
791
-
792
- ### Configuration
793
- - `getApiBaseUrl()` - Get current API base URL
794
- - `updateTelemetryConfig(config)` - Update client configuration
795
-
796
- ## Authentication Flow
797
-
798
- ### Modern Token Flow (Recommended)
799
- 1. User authenticates on platform
800
- 2. Platform generates hyve-token: `signature.address.random.timestamp`
801
- 3. Token passed via URL parameter `hyve-token`
802
- 4. SDK verifies token with `verifyHyveToken()` or `verifyAuthentication()`
803
306
 
804
- ### Legacy Token Flow
805
- 1. User signs message containing metadata (expiration, address)
806
- 2. Signature and message passed via URL parameters
807
- 3. SDK verifies with `handleVerifyMessage()` or `verifyAuthentication()`
307
+ | Method | Returns | Description |
308
+ |--------|---------|-------------|
309
+ | `getUserId()` | `string \| null` | Authenticated user ID |
310
+ | `getGameId()` | `string \| null` | Game ID from URL or JWT |
311
+ | `getSessionId()` | `string` | Unique session ID |
312
+ | `getJwtToken()` | `string \| null` | Raw JWT string |
313
+ | `isUserAuthenticated()` | `boolean` | Whether a user ID was extracted |
314
+ | `hasJwtToken()` | `boolean` | Whether a JWT is present |
315
+ | `logout()` | `void` | Clear auth state |
316
+ | `reset()` | `void` | Clear auth and generate new session ID |
317
+
318
+ ### API
319
+
320
+ | Method | Returns | Description |
321
+ |--------|---------|-------------|
322
+ | `callApi<T>(endpoint, options?)` | `Promise<T>` | Authenticated fetch to the Hyve API |
323
+ | `getInventory()` | `Promise<Inventory>` | Get user inventory |
324
+ | `getInventoryItem(itemId)` | `Promise<InventoryItem>` | Get a specific inventory item |
808
325
 
809
- ## Security Considerations
810
-
811
- - **Token Expiration**: Modern tokens expire after 10 minutes by default
812
- - **Domain Validation**: Always validate origin domains in production
813
- - **Signature Verification**: All signatures verified using ethers.js
814
- - **Localhost Exception**: localhost always allowed for development
815
-
816
- ## TypeScript Support
326
+ ### Telemetry
817
327
 
818
- Full TypeScript support with exported types for all utilities and return values.
328
+ | Method | Returns | Description |
329
+ |--------|---------|-------------|
330
+ | `sendTelemetry(location, category, action, subCategory?, subAction?, details?)` | `Promise<boolean>` | Send an analytics event |
331
+ | `updateTelemetryConfig(config)` | `void` | Update telemetry settings at runtime |
819
332
 
820
- ## Dependencies
333
+ ### Storage
821
334
 
822
- - **ethers**: ^6.13.7 - Ethereum signature verification
823
- - **uuid**: (peer dependency) - UUID generation
335
+ | Method | Returns | Description |
336
+ |--------|---------|-------------|
337
+ | `saveGameData(key, value, storage?)` | `Promise<SaveGameDataResponse>` | Save a single value |
338
+ | `batchSaveGameData(items, storage?)` | `Promise<SaveGameDataResponse>` | Save multiple values |
339
+ | `getGameData(key, storage?)` | `Promise<GameDataItem \| null>` | Get a single value |
340
+ | `getMultipleGameData(keys, storage?)` | `Promise<GameDataItem[]>` | Get multiple values |
341
+ | `deleteGameData(key, storage?)` | `Promise<boolean>` | Delete a single value |
342
+ | `deleteMultipleGameData(keys, storage?)` | `Promise<number>` | Delete multiple values |
343
+ | `configureStorage(mode)` | `void` | Set default storage mode |
344
+ | `getStorageMode()` | `"cloud" \| "local"` | Get current storage mode |
824
345
 
825
- ## Build Configuration
346
+ ### Ads
826
347
 
827
- The SDK builds to multiple formats:
828
- - CommonJS (`dist/index.js`)
829
- - ES Modules (`dist/index.mjs`)
830
- - TypeScript declarations (`dist/index.d.ts`)
348
+ | Method | Returns | Description |
349
+ |--------|---------|-------------|
350
+ | `configureAds(config)` | `void` | Configure the ads service |
351
+ | `showAd(type)` | `Promise<AdResult>` | Show an ad |
352
+ | `areAdsReady()` | `boolean` | Check if ads have initialized |
353
+ | `gameplayStart()` | `Promise<void>` | Notify gameplay started (CrazyGames) |
354
+ | `gameplayStop()` | `Promise<void>` | Notify gameplay stopped (CrazyGames) |
355
+ | `happytime()` | `Promise<void>` | Trigger celebration effect (CrazyGames) |
356
+
357
+ ### Billing
358
+
359
+ | Method | Returns | Description |
360
+ |--------|---------|-------------|
361
+ | `getBillingPlatform()` | `BillingPlatform` | `"web"` \| `"native"` \| `"unknown"` |
362
+ | `isBillingAvailable()` | `boolean` | Check if billing is ready |
363
+ | `getBillingProducts()` | `Promise<BillingProduct[]>` | Fetch available products |
364
+ | `purchaseProduct(productId, options?)` | `Promise<PurchaseResult>` | Initiate a purchase |
365
+ | `onPurchaseComplete(callback)` | `void` | Register purchase success handler |
366
+ | `onPurchaseError(callback)` | `void` | Register purchase error handler |
367
+ | `unmountBillingCheckout()` | `void` | Clean up Stripe checkout UI |
368
+
369
+ ## Build Output
370
+
371
+ | Format | File | Use |
372
+ |--------|------|-----|
373
+ | CJS | `dist/index.js` | Node.js / bundler |
374
+ | ESM | `dist/index.mjs` | Bundler (tree-shakeable) |
375
+ | CJS (React) | `dist/react.js` | React integration |
376
+ | ESM (React) | `dist/react.mjs` | React integration (tree-shakeable) |
831
377
 
832
378
  ## Development
833
379
 
834
380
  ```bash
835
- # Install dependencies
836
- bun install
837
-
838
- # Type checking
839
- bun run check-types
840
-
841
- # Linting
842
- bun run lint
843
-
844
- # Build
845
- bun run build
381
+ pnpm run check-types # Type check
382
+ pnpm run lint # Lint
383
+ pnpm run build # Build
846
384
  ```
847
385
 
848
- ## Documentation
849
-
850
- For complete documentation and examples, visit [https://docs.hyve.gg](https://docs.hyve.gg)
851
-
852
- ### Additional Guides
853
-
854
- - [Telemetry Guide](./docs/TELEMETRY.md) - Best practices, validation rules, and examples for event tracking
855
- - [Billing Integration](./docs/BILLING_INTEGRATION.md) - Platform-aware billing with Stripe and In-App Purchases
856
- - [Billing Migration Guide](./docs/BILLING_MIGRATION_GUIDE.md) - Upgrading from older billing implementations
857
- - [Ads Integration](./docs/ads.md) - Google H5 Games Ads integration
858
- - [Native Bridge](./docs/NATIVE_BRIDGE.md) - React Native WebView communication
859
-
860
386
  ## License
861
387
 
862
- MIT
388
+ MIT