@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 +255 -240
- package/dist/index.js +4 -2
- package/dist/index.mjs +4 -2
- package/dist/react.js +4 -2
- package/dist/react.mjs +4 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,339 +1,370 @@
|
|
|
1
1
|
# @hyve-sdk/js
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11
|
+
## Quick Start
|
|
14
12
|
|
|
15
|
-
```
|
|
16
|
-
|
|
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
|
-
|
|
19
|
+
console.log("User ID:", client.getUserId());
|
|
20
|
+
console.log("Game ID:", client.getGameId());
|
|
21
|
+
console.log("Authenticated:", client.isUserAuthenticated());
|
|
22
|
+
```
|
|
20
23
|
|
|
21
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
31
|
-
await client.authenticateFromUrl(window.location.search);
|
|
35
|
+
## React Integration
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
function App() {
|
|
43
|
+
return (
|
|
44
|
+
<HyveSdkProvider config={{ isDev: true }}>
|
|
45
|
+
<Game />
|
|
46
|
+
</HyveSdkProvider>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
41
49
|
|
|
42
|
-
|
|
50
|
+
function Game() {
|
|
51
|
+
const sdk = useHyveSdk();
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
const handleScore = () => {
|
|
54
|
+
sdk.sendTelemetry("game", "player", "score_submitted", null, null, { score: 1000 });
|
|
55
|
+
};
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
return <button onClick={handleScore}>Submit Score</button>;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
48
60
|
|
|
49
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{
|
|
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:
|
|
82
|
+
targetId: "enemy-123",
|
|
62
83
|
}
|
|
63
84
|
);
|
|
64
85
|
```
|
|
65
86
|
|
|
66
|
-
|
|
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
|
-
##
|
|
89
|
+
## Persistent Game Data
|
|
74
90
|
|
|
75
|
-
|
|
91
|
+
Save and retrieve game data with either cloud (default) or local storage:
|
|
76
92
|
|
|
77
|
-
```
|
|
78
|
-
//
|
|
79
|
-
|
|
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
|
-
//
|
|
82
|
-
const
|
|
83
|
-
|
|
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
|
-
|
|
102
|
+
// Batch save
|
|
103
|
+
await client.batchSaveGameData([
|
|
104
|
+
{ key: "coins", value: 1200 },
|
|
105
|
+
{ key: "lives", value: 3 },
|
|
106
|
+
]);
|
|
89
107
|
|
|
90
|
-
|
|
91
|
-
const
|
|
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
|
-
|
|
111
|
+
// Delete
|
|
112
|
+
await client.deleteGameData("temp_key");
|
|
113
|
+
await client.deleteMultipleGameData(["key1", "key2"]);
|
|
98
114
|
```
|
|
99
115
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
Ads are **disabled by default** — must be explicitly enabled.
|
|
116
|
+
### Storage Modes
|
|
103
117
|
|
|
104
|
-
|
|
118
|
+
```ts
|
|
119
|
+
// Set mode at construction
|
|
120
|
+
const client = new HyveClient({ storageMode: "local" });
|
|
105
121
|
|
|
106
|
-
|
|
122
|
+
// Or override per-call
|
|
123
|
+
await client.saveGameData("key", "value", "local");
|
|
124
|
+
await client.getGameData("key", "cloud");
|
|
107
125
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
131
|
+
| Mode | Description |
|
|
132
|
+
|------|-------------|
|
|
133
|
+
| `cloud` | Synced to backend API (default) |
|
|
134
|
+
| `local` | Browser `localStorage`, device-only |
|
|
122
135
|
|
|
123
|
-
|
|
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.
|
|
136
|
-
|
|
137
|
-
const result = await client.showAd('rewarded');
|
|
150
|
+
const result = await client.showAd("rewarded");
|
|
138
151
|
if (result.success) {
|
|
139
|
-
console.log(
|
|
152
|
+
console.log("User watched the ad");
|
|
140
153
|
}
|
|
141
154
|
|
|
142
|
-
await client.showAd(
|
|
143
|
-
await client.showAd(
|
|
155
|
+
await client.showAd("interstitial"); // between levels
|
|
156
|
+
await client.showAd("preroll"); // game start
|
|
144
157
|
```
|
|
145
158
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
|
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
|
-
|
|
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
|
-
##
|
|
167
|
+
## Platform Integrations
|
|
157
168
|
|
|
158
|
-
|
|
169
|
+
### CrazyGames
|
|
159
170
|
|
|
160
|
-
|
|
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
|
-
```
|
|
163
|
-
|
|
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:
|
|
168
|
-
|
|
169
|
-
}
|
|
195
|
+
stripePublishableKey: "pk_live_...",
|
|
196
|
+
},
|
|
170
197
|
});
|
|
171
198
|
|
|
172
|
-
|
|
173
|
-
const initialized = await client.initializeBilling();
|
|
174
|
-
|
|
175
|
-
if (initialized && client.isBillingAvailable()) {
|
|
199
|
+
if (client.isBillingAvailable()) {
|
|
176
200
|
client.onPurchaseComplete((result) => {
|
|
177
|
-
console.log(
|
|
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(
|
|
205
|
+
console.error("Purchase failed:", result.error?.message);
|
|
183
206
|
});
|
|
184
207
|
|
|
185
208
|
const products = await client.getBillingProducts();
|
|
186
|
-
await client.purchaseProduct(
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
224
|
+
## Native Bridge
|
|
210
225
|
|
|
211
|
-
|
|
226
|
+
Type-safe bidirectional communication between your web game and a React Native WebView host.
|
|
212
227
|
|
|
213
|
-
```
|
|
214
|
-
|
|
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
|
-
|
|
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
|
-
|
|
224
|
-
NativeBridge.on(
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
234
|
-
|
|
235
|
-
```js
|
|
236
|
-
NativeBridge.on('PUSH_PERMISSION_GRANTED', (payload) => {
|
|
237
|
-
console.log('Token:', payload?.token);
|
|
238
|
-
});
|
|
256
|
+
### NativeBridge API
|
|
239
257
|
|
|
240
|
-
|
|
241
|
-
|
|
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
|
-
|
|
245
|
-
```
|
|
269
|
+
## Logger
|
|
246
270
|
|
|
247
|
-
|
|
271
|
+
```ts
|
|
272
|
+
import { logger } from "@hyve-sdk/js";
|
|
248
273
|
|
|
249
|
-
|
|
250
|
-
|
|
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
|
-
|
|
253
|
-
|
|
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
|
-
|
|
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
|
-
|
|
288
|
+
localStorage.setItem("HYVE_SDK_LOG_LEVEL", "error,warn");
|
|
289
|
+
```
|
|
274
290
|
|
|
275
|
-
|
|
276
|
-
logger.info('Informational message');
|
|
277
|
-
logger.warn('Warning message');
|
|
278
|
-
logger.error('Error message', error);
|
|
291
|
+
## API Reference
|
|
279
292
|
|
|
280
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
-
|
|
311
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
|
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
|
-
#
|
|
350
|
-
|
|
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
|
-
|
|
1936
|
-
|
|
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
|
-
|
|
1896
|
-
|
|
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
|
-
|
|
1887
|
-
|
|
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
|
-
|
|
1866
|
-
|
|
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.
|
|
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/
|
|
72
|
-
"@repo/
|
|
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",
|