@hyve-sdk/js 2.1.0 → 2.1.2

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,339 +1,370 @@
1
1
  # @hyve-sdk/js
2
2
 
3
- The core SDK for integrating with the Hyve platform, providing authentication, telemetry, persistent storage, billing, ads, and native bridge capabilities for web games.
3
+ TypeScript SDK for integrating games with the Hyve platform. Provides authentication, telemetry, persistent storage, ads, billing, and native bridge capabilities.
4
4
 
5
- ## Setup
5
+ ## Installation
6
6
 
7
- Load the SDK via script tag — no npm install required.
8
-
9
- ```html
10
- <script src="https://package.hyve.gg/hyve-sdk.global.js"></script>
7
+ ```bash
8
+ pnpm add @hyve-sdk/js
11
9
  ```
12
10
 
13
- All exports are available on `window.HyveSDK`:
11
+ ## Quick Start
14
12
 
15
- ```js
16
- const { HyveClient, NativeBridge, NativeMessageType } = window.HyveSDK;
17
- ```
13
+ ```ts
14
+ import { HyveClient } from "@hyve-sdk/js";
15
+
16
+ // Authentication is automatic — the SDK reads hyve-access and game-id from the URL
17
+ const client = new HyveClient();
18
18
 
19
- ## Authentication
19
+ console.log("User ID:", client.getUserId());
20
+ console.log("Game ID:", client.getGameId());
21
+ console.log("Authenticated:", client.isUserAuthenticated());
22
+ ```
20
23
 
21
- Authenticate using the `hyve-access` JWT passed in the URL:
24
+ The SDK reads authentication from URL parameters automatically during construction:
22
25
 
23
26
  ```
24
27
  https://your-game.com?hyve-access=eyJhbGci...&game-id=my-game
25
28
  ```
26
29
 
27
- ```js
28
- const { HyveClient } = window.HyveSDK;
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
29
34
 
30
- const client = new HyveClient();
31
- await client.authenticateFromUrl(window.location.search);
35
+ ## React Integration
32
36
 
33
- console.log('User ID:', client.getUserId());
34
- console.log('Game ID:', client.getGameId());
35
- ```
37
+ Import from `@hyve-sdk/js/react` for the React provider and hook:
38
+
39
+ ```tsx
40
+ import { HyveSdkProvider, useHyveSdk } from "@hyve-sdk/js/react";
36
41
 
37
- **Environment Detection:**
38
- The SDK automatically detects dev vs prod by checking the parent page URL:
39
- - **Dev**: `marvin.dev.hyve.gg` or `dev.hyve.gg`
40
- - **Prod**: `marvin.hyve.gg` or `hyve.gg`
42
+ function App() {
43
+ return (
44
+ <HyveSdkProvider config={{ isDev: true }}>
45
+ <Game />
46
+ </HyveSdkProvider>
47
+ );
48
+ }
41
49
 
42
- ## Telemetry & Analytics
50
+ function Game() {
51
+ const sdk = useHyveSdk();
43
52
 
44
- Track user actions and game events:
53
+ const handleScore = () => {
54
+ sdk.sendTelemetry("game", "player", "score_submitted", null, null, { score: 1000 });
55
+ };
45
56
 
46
- ```js
47
- const { HyveClient } = window.HyveSDK;
57
+ return <button onClick={handleScore}>Submit Score</button>;
58
+ }
59
+ ```
48
60
 
49
- const client = new HyveClient();
50
- await client.authenticateFromUrl(window.location.search);
61
+ You can also pass a pre-created client:
51
62
 
63
+ ```tsx
64
+ const client = new HyveClient({ isDev: true });
65
+
66
+ <HyveSdkProvider client={client}>
67
+ <App />
68
+ </HyveSdkProvider>
69
+ ```
70
+
71
+ ## Telemetry
72
+
73
+ ```ts
52
74
  await client.sendTelemetry(
53
- 'game', // location
54
- 'player', // category
55
- 'action', // action
56
- 'combat', // sub-category (optional)
57
- 'attack', // sub-action (optional)
58
- { // event details (optional)
59
- button: 'attack-btn',
75
+ "game", // location
76
+ "player", // category
77
+ "action", // action
78
+ "combat", // sub-category (optional)
79
+ "attack", // sub-action (optional)
80
+ { // event details (optional)
60
81
  damage: 100,
61
- targetId: 'enemy-123',
82
+ targetId: "enemy-123",
62
83
  }
63
84
  );
64
85
  ```
65
86
 
66
- **Requirements:**
67
- - `hyve-access` JWT in URL
68
- - `game-id` in URL or JWT
69
- - User authenticated via `authenticateFromUrl`
70
-
71
- See [docs/TELEMETRY.md](./docs/TELEMETRY.md) for validation rules and examples.
87
+ Requires a valid `hyve-access` JWT and `game-id` in the URL.
72
88
 
73
- ## API Integration
89
+ ## Persistent Game Data
74
90
 
75
- ### Generic API Calls
91
+ Save and retrieve game data with either cloud (default) or local storage:
76
92
 
77
- ```js
78
- // GET request
79
- const userData = await client.callApi('/api/v1/user');
93
+ ```ts
94
+ // Save a value
95
+ await client.saveGameData("player_level", 5);
96
+ await client.saveGameData("settings", { volume: 0.8, fullscreen: true });
80
97
 
81
- // POST request
82
- const result = await client.callApi('/api/v1/game/score', {
83
- method: 'POST',
84
- body: JSON.stringify({ score: 1000 })
85
- });
86
- ```
98
+ // Get a value
99
+ const item = await client.getGameData("player_level");
100
+ console.log(item?.value); // 5
87
101
 
88
- ### Inventory
102
+ // Batch save
103
+ await client.batchSaveGameData([
104
+ { key: "coins", value: 1200 },
105
+ { key: "lives", value: 3 },
106
+ ]);
89
107
 
90
- ```js
91
- const inventory = await client.getInventory();
92
- console.log(`Total items: ${inventory.total_count}`);
93
- inventory.items.forEach(item => {
94
- console.log(`${item.item_type}: ${item.quantity}x`);
95
- });
108
+ // Batch get
109
+ const items = await client.getMultipleGameData(["coins", "lives"]);
96
110
 
97
- const item = await client.getInventoryItem('item-id-123');
111
+ // Delete
112
+ await client.deleteGameData("temp_key");
113
+ await client.deleteMultipleGameData(["key1", "key2"]);
98
114
  ```
99
115
 
100
- ## Ads Integration
101
-
102
- Ads are **disabled by default** — must be explicitly enabled.
116
+ ### Storage Modes
103
117
 
104
- ### Prerequisites
118
+ ```ts
119
+ // Set mode at construction
120
+ const client = new HyveClient({ storageMode: "local" });
105
121
 
106
- Add the Google H5 Games Ads SDK to your HTML before the Hyve SDK:
122
+ // Or override per-call
123
+ await client.saveGameData("key", "value", "local");
124
+ await client.getGameData("key", "cloud");
107
125
 
108
- ```html
109
- <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
110
- <script>
111
- window.adBreak = window.adBreak || function(o) {
112
- (window.adsbygoogle = window.adsbygoogle || []).push(o);
113
- };
114
- window.adConfig = window.adConfig || function(o) {
115
- (window.adsbygoogle = window.adsbygoogle || []).push(o);
116
- };
117
- </script>
118
- <script src="https://package.hyve.gg/hyve-sdk.global.js"></script>
126
+ // Change mode at runtime
127
+ client.configureStorage("cloud");
128
+ console.log(client.getStorageMode()); // "cloud"
119
129
  ```
120
130
 
121
- ### Quick Start
131
+ | Mode | Description |
132
+ |------|-------------|
133
+ | `cloud` | Synced to backend API (default) |
134
+ | `local` | Browser `localStorage`, device-only |
122
135
 
123
- ```js
124
- const { HyveClient } = window.HyveSDK;
136
+ ## Ads
125
137
 
138
+ Ads are disabled by default and must be explicitly configured.
139
+
140
+ ```ts
126
141
  const client = new HyveClient({
127
142
  ads: {
128
143
  enabled: true,
129
144
  onBeforeAd: (type) => game.pause(),
130
145
  onAfterAd: (type) => game.resume(),
131
- onRewardEarned: () => { player.coins += 100; }
132
- }
146
+ onRewardEarned: () => { player.coins += 100; },
147
+ },
133
148
  });
134
149
 
135
- await client.authenticateFromUrl(window.location.search);
136
-
137
- const result = await client.showAd('rewarded');
150
+ const result = await client.showAd("rewarded");
138
151
  if (result.success) {
139
- console.log('User watched the ad!');
152
+ console.log("User watched the ad");
140
153
  }
141
154
 
142
- await client.showAd('interstitial'); // Between levels
143
- await client.showAd('preroll'); // Game start
155
+ await client.showAd("interstitial"); // between levels
156
+ await client.showAd("preroll"); // game start
144
157
  ```
145
158
 
146
- ### Ad Types
147
-
148
- | Type | Use Case |
149
- |------|----------|
150
- | `rewarded` | User watches full ad for reward |
159
+ | Ad Type | Use Case |
160
+ |---------|----------|
161
+ | `rewarded` | User watches full ad for a reward |
151
162
  | `interstitial` | Between levels or game screens |
152
- | `preroll` | Before game starts |
163
+ | `preroll` | Before the game starts |
153
164
 
154
- See [docs/ads.md](./docs/ads.md) for detailed documentation.
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.
155
166
 
156
- ## Billing Integration
167
+ ## Platform Integrations
157
168
 
158
- Unified billing for web (Stripe) and native (In-App Purchases). Platform is detected automatically.
169
+ ### CrazyGames
159
170
 
160
- ### Quick Start
171
+ When running on CrazyGames, the SDK auto-initializes the CrazyGames SDK and routes ads through it. Use these additional lifecycle methods:
161
172
 
162
- ```js
163
- const { HyveClient } = window.HyveSDK;
173
+ ```ts
174
+ // Call when gameplay begins (required by CrazyGames policy)
175
+ await client.gameplayStart();
176
+
177
+ // Call when gameplay stops (paused, died, menu, etc.)
178
+ await client.gameplayStop();
179
+
180
+ // Trigger a celebration effect on the CrazyGames website
181
+ await client.happytime();
182
+ ```
183
+
184
+ ### Playgama
164
185
 
186
+ When running on Playgama, the SDK auto-initializes the Playgama Bridge and routes ads through it. No additional setup required.
187
+
188
+ ## Billing
189
+
190
+ Billing supports web (Stripe) and native (In-App Purchases) — platform is detected automatically.
191
+
192
+ ```ts
165
193
  const client = new HyveClient({
166
194
  billing: {
167
- stripePublishableKey: 'pk_live_...',
168
- checkoutUrl: 'https://checkout-api.hyve.gg',
169
- }
195
+ stripePublishableKey: "pk_live_...",
196
+ },
170
197
  });
171
198
 
172
- await client.authenticateFromUrl(window.location.search);
173
- const initialized = await client.initializeBilling();
174
-
175
- if (initialized && client.isBillingAvailable()) {
199
+ if (client.isBillingAvailable()) {
176
200
  client.onPurchaseComplete((result) => {
177
- console.log('Purchase successful!', result.transactionId);
178
- client.getInventory().then(inv => console.log('Updated inventory:', inv));
201
+ console.log("Purchase successful:", result.transactionId);
179
202
  });
180
203
 
181
204
  client.onPurchaseError((result) => {
182
- console.error('Purchase failed:', result.error?.message);
205
+ console.error("Purchase failed:", result.error?.message);
183
206
  });
184
207
 
185
208
  const products = await client.getBillingProducts();
186
- await client.purchaseProduct('price_1234');
209
+ await client.purchaseProduct("price_1234");
187
210
  }
188
211
  ```
189
212
 
190
- ### Platform Support
191
-
192
- | Platform | Payment Method | Detection |
193
- |----------|---------------|-----------|
194
- | Web | Stripe Embedded Checkout | Default (no ReactNativeWebView) |
195
- | Native (iOS/Android) | In-App Purchases | `ReactNativeWebView` in window |
196
-
197
- ### Prerequisites
198
-
199
213
  For web, add a container element for the Stripe checkout UI:
200
214
 
201
215
  ```html
202
216
  <div id="stripe-checkout-element"></div>
203
217
  ```
204
218
 
205
- See [docs/BILLING_INTEGRATION.md](./docs/BILLING_INTEGRATION.md) for full documentation and examples.
206
-
207
- ## Native Bridge (React Native WebView)
219
+ | Platform | Payment Method | Detection |
220
+ |----------|---------------|-----------|
221
+ | Web | Stripe Embedded Checkout | Default |
222
+ | Native iOS/Android | In-App Purchases | `ReactNativeWebView` in window |
208
223
 
209
- Type-safe bidirectional communication between your web game and a React Native mobile app.
224
+ ## Native Bridge
210
225
 
211
- ### Quick Start
226
+ Type-safe bidirectional communication between your web game and a React Native WebView host.
212
227
 
213
- ```js
214
- const { NativeBridge } = window.HyveSDK;
228
+ ```ts
229
+ import { NativeBridge } from "@hyve-sdk/js";
215
230
 
216
231
  if (NativeBridge.isNativeContext()) {
217
232
  NativeBridge.initialize();
218
- }
219
- ```
220
233
 
221
- ### IAP Availability
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();
222
241
 
223
- ```js
224
- NativeBridge.on('IAP_AVAILABILITY_RESULT', (payload) => {
225
- if (payload.available) {
226
- console.log('IAP available on platform:', payload.platform);
227
- }
228
- });
242
+ // Request push notification permission
243
+ NativeBridge.on("PUSH_PERMISSION_GRANTED", (payload) => {
244
+ console.log("Token:", payload?.token);
245
+ });
246
+ NativeBridge.requestNotificationPermission();
229
247
 
230
- NativeBridge.checkIAPAvailability();
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
+ }
231
254
  ```
232
255
 
233
- ### Push Notifications
234
-
235
- ```js
236
- NativeBridge.on('PUSH_PERMISSION_GRANTED', (payload) => {
237
- console.log('Token:', payload?.token);
238
- });
256
+ ### NativeBridge API
239
257
 
240
- NativeBridge.on('PUSH_PERMISSION_DENIED', () => {
241
- console.log('Permission denied');
242
- });
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 |
243
268
 
244
- NativeBridge.requestNotificationPermission();
245
- ```
269
+ ## Logger
246
270
 
247
- ### Custom Messages
271
+ ```ts
272
+ import { logger } from "@hyve-sdk/js";
248
273
 
249
- ```js
250
- NativeBridge.send('GAME_EVENT', { action: 'level_complete', level: 3 });
274
+ logger.debug("Debug info", { data: "value" });
275
+ logger.info("Informational message");
276
+ logger.warn("Warning message");
277
+ logger.error("Error message", error);
251
278
 
252
- NativeBridge.on('CUSTOM_RESPONSE', (payload) => {
253
- console.log('Received:', payload);
254
- });
279
+ // Namespaced child logger
280
+ const gameLogger = logger.child("Game");
281
+ gameLogger.info("Game started");
282
+ // Output: [Hyve SDK] [Game] [INFO] [timestamp] Game started
255
283
  ```
256
284
 
257
- ### API Reference
258
-
259
- - `NativeBridge.isNativeContext()` — Check if running in React Native WebView
260
- - `NativeBridge.initialize()` — Start message listener
261
- - `NativeBridge.send(type, payload?)` — Send message to native
262
- - `NativeBridge.on(type, handler)` — Register message handler
263
- - `NativeBridge.off(type)` — Remove message handler
264
- - `NativeBridge.clearHandlers()` — Remove all handlers
265
- - `NativeBridge.checkIAPAvailability()` — Request IAP availability
266
- - `NativeBridge.requestNotificationPermission()` — Request notification permission
267
-
268
- See [docs/NATIVE_BRIDGE.md](./docs/NATIVE_BRIDGE.md) for full documentation.
269
-
270
- ## Logger
285
+ Override log level in the browser:
271
286
 
272
287
  ```js
273
- const { logger } = window.HyveSDK;
288
+ localStorage.setItem("HYVE_SDK_LOG_LEVEL", "error,warn");
289
+ ```
274
290
 
275
- logger.debug('Debug info', { data: 'value' });
276
- logger.info('Informational message');
277
- logger.warn('Warning message');
278
- logger.error('Error message', error);
291
+ ## API Reference
279
292
 
280
- // Namespaced child loggers
281
- const gameLogger = logger.child('Game');
282
- gameLogger.info('Game started');
283
- // Output: [Hyve SDK] [Game] [INFO] [timestamp] Game started
284
- ```
293
+ ### HyveClient Config
285
294
 
286
- **Log level override (browser):**
287
- ```js
288
- localStorage.setItem('HYVE_SDK_LOG_LEVEL', 'error,warn');
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
+ })
289
303
  ```
290
304
 
291
- ## Client Methods Reference
292
-
293
305
  ### Authentication
294
- - `authenticateFromUrl(urlParams)` — Extract JWT and game ID from URL, authenticate user
295
- - `getUserId()` Authenticated user ID
296
- - `getSessionId()` — Unique session ID
297
- - `getGameId()` Game ID from URL or JWT
298
- - `isUserAuthenticated()` Check if authenticated
299
- - `hasJwtToken()` Check if JWT available
300
- - `getJwtToken()` Get JWT string
301
- - `logout()` Clear authentication
302
- - `reset()` Reset client state
306
+
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 |
303
317
 
304
318
  ### API
305
- - `callApi<T>(endpoint, options?)` — Authenticated API call
306
- - `getInventory()` Get user inventory
307
- - `getInventoryItem(itemId)` — Get specific inventory item
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 |
308
325
 
309
326
  ### Telemetry
310
- - `sendTelemetry(location, category, action, subCategory?, subAction?, details?)` — Send analytics event
311
- - `updateTelemetryConfig(config)` Update telemetry settings
327
+
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 |
332
+
333
+ ### Storage
334
+
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 |
312
345
 
313
346
  ### Ads
314
- - `configureAds(config)` — Configure ads service
315
- - `showAd(type)` Show an ad (`'rewarded'` | `'interstitial'` | `'preroll'`)
316
- - `areAdsEnabled()` — Check if ads are enabled
317
- - `areAdsReady()` Check if ads are ready
347
+
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) |
318
356
 
319
357
  ### Billing
320
- - `configureBilling(config)` — Configure billing service
321
- - `initializeBilling()` Initialize billing (resolves platform automatically)
322
- - `getBillingPlatform()` — `'web'` | `'native'` | `'unknown'`
323
- - `isBillingAvailable()` Check if billing is ready
324
- - `getBillingProducts()` Fetch available products
325
- - `purchaseProduct(productId, options?)` Initiate purchase
326
- - `onPurchaseComplete(callback)` Register purchase success handler
327
- - `onPurchaseError(callback)` Register purchase error handler
328
- - `unmountBillingCheckout()` Clean up Stripe checkout UI
329
-
330
- ## Security Considerations
331
-
332
- - Never expose secret keys in game code
333
- - Always validate receipts server-side
334
- - Use HTTPS for all requests
335
- - Don't trust client-reported prices
336
- - Verify user authentication before crediting purchases
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 |
337
368
 
338
369
  ## Build Output
339
370
 
@@ -341,33 +372,17 @@ localStorage.setItem('HYVE_SDK_LOG_LEVEL', 'error,warn');
341
372
  |--------|------|-----|
342
373
  | CJS | `dist/index.js` | Node.js / bundler |
343
374
  | ESM | `dist/index.mjs` | Bundler (tree-shakeable) |
344
- | IIFE | `dist/hyve-sdk.global.js` | CDN / script tag |
375
+ | CJS (React) | `dist/react.js` | React integration |
376
+ | ESM (React) | `dist/react.mjs` | React integration (tree-shakeable) |
345
377
 
346
378
  ## Development
347
379
 
348
380
  ```bash
349
- # Install dependencies
350
- bun install
351
-
352
- # Type checking
353
- bun run check-types
354
-
355
- # Linting
356
- bun run lint
357
-
358
- # Build
359
- bun run build
381
+ pnpm run check-types # Type check
382
+ pnpm run lint # Lint
383
+ pnpm run build # Build
360
384
  ```
361
385
 
362
- ## Documentation
363
-
364
- - [Telemetry Guide](./docs/TELEMETRY.md)
365
- - [Billing Integration](./docs/BILLING_INTEGRATION.md)
366
- - [Billing Migration Guide](./docs/BILLING_MIGRATION_GUIDE.md)
367
- - [Ads Integration](./docs/ads.md)
368
- - [Native Bridge](./docs/NATIVE_BRIDGE.md)
369
- - [Platform-Aware Billing](./docs/PLATFORM_AWARE_BILLING.md)
370
-
371
386
  ## License
372
387
 
373
388
  MIT
package/dist/index.js CHANGED
@@ -1932,8 +1932,10 @@ var HyveClient = class {
1932
1932
  * Returns the current game ID or throws if not available.
1933
1933
  */
1934
1934
  requireGameId() {
1935
- const gameId = this.requireGameId();
1936
- return gameId;
1935
+ if (!this.gameId) {
1936
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1937
+ }
1938
+ return this.gameId;
1937
1939
  }
1938
1940
  /**
1939
1941
  * Save persistent game data
package/dist/index.mjs CHANGED
@@ -1892,8 +1892,10 @@ var HyveClient = class {
1892
1892
  * Returns the current game ID or throws if not available.
1893
1893
  */
1894
1894
  requireGameId() {
1895
- const gameId = this.requireGameId();
1896
- return gameId;
1895
+ if (!this.gameId) {
1896
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1897
+ }
1898
+ return this.gameId;
1897
1899
  }
1898
1900
  /**
1899
1901
  * Save persistent game data
package/dist/react.js CHANGED
@@ -1883,8 +1883,10 @@ var HyveClient = class {
1883
1883
  * Returns the current game ID or throws if not available.
1884
1884
  */
1885
1885
  requireGameId() {
1886
- const gameId = this.requireGameId();
1887
- return gameId;
1886
+ if (!this.gameId) {
1887
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1888
+ }
1889
+ return this.gameId;
1888
1890
  }
1889
1891
  /**
1890
1892
  * Save persistent game data
package/dist/react.mjs CHANGED
@@ -1862,8 +1862,10 @@ var HyveClient = class {
1862
1862
  * Returns the current game ID or throws if not available.
1863
1863
  */
1864
1864
  requireGameId() {
1865
- const gameId = this.requireGameId();
1866
- return gameId;
1865
+ if (!this.gameId) {
1866
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1867
+ }
1868
+ return this.gameId;
1867
1869
  }
1868
1870
  /**
1869
1871
  * Save persistent game data
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyve-sdk/js",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Hyve SDK - TypeScript wrapper for Hyve game server integration",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -68,8 +68,8 @@
68
68
  "@types/uuid": "^10.0.0",
69
69
  "tsup": "^8.4.0",
70
70
  "typescript": "^5.3.3",
71
- "@repo/eslint-config": "0.0.0",
72
- "@repo/typescript-config": "0.0.0"
71
+ "@repo/typescript-config": "0.0.0",
72
+ "@repo/eslint-config": "0.0.0"
73
73
  },
74
74
  "scripts": {
75
75
  "lint": "eslint . --max-warnings 0",