@hyve-sdk/js 2.4.0 → 2.4.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 +123 -64
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,53 +5,27 @@ TypeScript SDK for integrating games with the Hyve platform. Provides authentica
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
bun add @hyve-sdk/js
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
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
|
-
|
|
19
|
-
console.log("User ID:", client.getUserId());
|
|
20
|
-
console.log("Game ID:", client.getGameId());
|
|
21
|
-
console.log("Authenticated:", client.isUserAuthenticated());
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
The SDK reads authentication from URL parameters automatically during construction:
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
https://your-game.com?hyve-access=eyJhbGci...&game-id=my-game
|
|
28
|
-
```
|
|
29
|
-
|
|
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
|
|
34
|
-
|
|
35
|
-
## React Integration
|
|
36
|
-
|
|
37
|
-
Import from `@hyve-sdk/js/react` for the React provider and hook:
|
|
38
|
-
|
|
39
13
|
```tsx
|
|
40
14
|
import { HyveSdkProvider, useHyveSdk } from "@hyve-sdk/js/react";
|
|
41
15
|
|
|
42
16
|
function App() {
|
|
43
17
|
return (
|
|
44
|
-
<HyveSdkProvider
|
|
18
|
+
<HyveSdkProvider>
|
|
45
19
|
<Game />
|
|
46
20
|
</HyveSdkProvider>
|
|
47
21
|
);
|
|
48
22
|
}
|
|
49
23
|
|
|
50
24
|
function Game() {
|
|
51
|
-
const
|
|
25
|
+
const hyve = useHyveSdk();
|
|
52
26
|
|
|
53
27
|
const handleScore = () => {
|
|
54
|
-
|
|
28
|
+
hyve.sendTelemetry("game", "player", "score_submitted", null, null, { score: 1000 });
|
|
55
29
|
};
|
|
56
30
|
|
|
57
31
|
return <button onClick={handleScore}>Submit Score</button>;
|
|
@@ -61,17 +35,32 @@ function Game() {
|
|
|
61
35
|
You can also pass a pre-created client:
|
|
62
36
|
|
|
63
37
|
```tsx
|
|
64
|
-
|
|
38
|
+
import { HyveClient } from "@hyve-sdk/js";
|
|
39
|
+
import { HyveSdkProvider } from "@hyve-sdk/js/react";
|
|
40
|
+
|
|
41
|
+
const client = new HyveClient();
|
|
65
42
|
|
|
66
43
|
<HyveSdkProvider client={client}>
|
|
67
44
|
<App />
|
|
68
45
|
</HyveSdkProvider>
|
|
69
46
|
```
|
|
70
47
|
|
|
48
|
+
The SDK reads authentication from URL parameters automatically during construction:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
https://your-game.com?hyve-access=eyJhbGci...&game-id=my-game
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Environment detection** happens automatically from the parent page URL (games run in iframes):
|
|
55
|
+
- Dev: `marvin.dev.hyve.gg` or `dev.hyve.gg`
|
|
56
|
+
- Prod: `marvin.hyve.gg` or `hyve.gg`
|
|
57
|
+
|
|
71
58
|
## Telemetry
|
|
72
59
|
|
|
73
60
|
```ts
|
|
74
|
-
|
|
61
|
+
const hyve = useHyveSdk();
|
|
62
|
+
|
|
63
|
+
await hyve.sendTelemetry(
|
|
75
64
|
"game", // location
|
|
76
65
|
"player", // category
|
|
77
66
|
"action", // action
|
|
@@ -80,7 +69,8 @@ await client.sendTelemetry(
|
|
|
80
69
|
{ // event details (optional)
|
|
81
70
|
damage: 100,
|
|
82
71
|
targetId: "enemy-123",
|
|
83
|
-
}
|
|
72
|
+
},
|
|
73
|
+
"playgama" // platform ID (optional)
|
|
84
74
|
);
|
|
85
75
|
```
|
|
86
76
|
|
|
@@ -91,26 +81,34 @@ Requires a valid `hyve-access` JWT and `game-id` in the URL.
|
|
|
91
81
|
Save and retrieve game data with either cloud (default) or local storage:
|
|
92
82
|
|
|
93
83
|
```ts
|
|
84
|
+
const hyve = useHyveSdk();
|
|
85
|
+
|
|
94
86
|
// Save a value
|
|
95
|
-
await
|
|
96
|
-
await
|
|
87
|
+
await hyve.saveGameData("player_level", 5);
|
|
88
|
+
await hyve.saveGameData("settings", { volume: 0.8, fullscreen: true });
|
|
89
|
+
|
|
90
|
+
// Atomic operations — read-modify-write server-side
|
|
91
|
+
await hyve.saveGameData("coins", 100, "add"); // increment
|
|
92
|
+
await hyve.saveGameData("high_score", 9999, "max"); // keep highest
|
|
93
|
+
await hyve.saveGameData("stats", 1, "add", "level"); // nested path
|
|
97
94
|
|
|
98
95
|
// Get a value
|
|
99
|
-
const item = await
|
|
96
|
+
const item = await hyve.getGameData("player_level");
|
|
100
97
|
console.log(item?.value); // 5
|
|
101
98
|
|
|
102
|
-
// Batch save
|
|
103
|
-
await
|
|
99
|
+
// Batch save (per-item operations supported)
|
|
100
|
+
await hyve.batchSaveGameData([
|
|
104
101
|
{ key: "coins", value: 1200 },
|
|
105
102
|
{ key: "lives", value: 3 },
|
|
103
|
+
{ key: "high_score", value: 5000, operation: "max" },
|
|
106
104
|
]);
|
|
107
105
|
|
|
108
106
|
// Batch get
|
|
109
|
-
const items = await
|
|
107
|
+
const items = await hyve.getMultipleGameData(["coins", "lives"]);
|
|
110
108
|
|
|
111
109
|
// Delete
|
|
112
|
-
await
|
|
113
|
-
await
|
|
110
|
+
await hyve.deleteGameData("temp_key");
|
|
111
|
+
await hyve.deleteMultipleGameData(["key1", "key2"]);
|
|
114
112
|
```
|
|
115
113
|
|
|
116
114
|
### Storage Modes
|
|
@@ -119,13 +117,13 @@ await client.deleteMultipleGameData(["key1", "key2"]);
|
|
|
119
117
|
// Set mode at construction
|
|
120
118
|
const client = new HyveClient({ storageMode: "local" });
|
|
121
119
|
|
|
122
|
-
// Or override per-call
|
|
123
|
-
await
|
|
124
|
-
await
|
|
120
|
+
// Or override per-call (storage is the last parameter)
|
|
121
|
+
await hyve.saveGameData("key", "value", undefined, undefined, "local");
|
|
122
|
+
await hyve.getGameData("key", "cloud");
|
|
125
123
|
|
|
126
124
|
// Change mode at runtime
|
|
127
|
-
|
|
128
|
-
console.log(
|
|
125
|
+
hyve.configureStorage("cloud");
|
|
126
|
+
console.log(hyve.getStorageMode()); // "cloud"
|
|
129
127
|
```
|
|
130
128
|
|
|
131
129
|
| Mode | Description |
|
|
@@ -133,11 +131,52 @@ console.log(client.getStorageMode()); // "cloud"
|
|
|
133
131
|
| `cloud` | Synced to backend API (default) |
|
|
134
132
|
| `local` | Browser `localStorage`, device-only |
|
|
135
133
|
|
|
134
|
+
## Leaderboards
|
|
135
|
+
|
|
136
|
+
Rank players by numeric values stored in persistent game data.
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
const hyve = useHyveSdk();
|
|
140
|
+
|
|
141
|
+
// 1. Store the player's score
|
|
142
|
+
await hyve.saveGameData("high_score", 4200);
|
|
143
|
+
|
|
144
|
+
// 2. Fetch the leaderboard
|
|
145
|
+
const board = await hyve.getGameDataLeaderboard({ key: "high_score" });
|
|
146
|
+
|
|
147
|
+
for (const entry of board.entries) {
|
|
148
|
+
console.log(`#${entry.rank} ${entry.username}: ${entry.score}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// The caller's own rank is included automatically
|
|
152
|
+
if (board.user_position) {
|
|
153
|
+
console.log("Your rank:", board.user_position.rank);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Use `score_path` to rank by a nested field, and `sort`/`limit`/`cursor` for pagination:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
const board = await hyve.getGameDataLeaderboard({
|
|
161
|
+
key: "tetris_progress",
|
|
162
|
+
score_path: "stats.score", // dot-notation path to numeric field
|
|
163
|
+
sort: "desc", // "asc" | "desc" (default: "desc")
|
|
164
|
+
limit: 20, // 1–100 (default: 10)
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (board.has_more && board.next_cursor) {
|
|
168
|
+
const next = await hyve.getGameDataLeaderboard({
|
|
169
|
+
key: "tetris_progress",
|
|
170
|
+
cursor: board.next_cursor,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
136
175
|
## Ads
|
|
137
176
|
|
|
138
177
|
Ads are disabled by default and must be explicitly configured.
|
|
139
178
|
|
|
140
|
-
```
|
|
179
|
+
```tsx
|
|
141
180
|
const client = new HyveClient({
|
|
142
181
|
ads: {
|
|
143
182
|
enabled: true,
|
|
@@ -147,13 +186,21 @@ const client = new HyveClient({
|
|
|
147
186
|
},
|
|
148
187
|
});
|
|
149
188
|
|
|
150
|
-
|
|
189
|
+
<HyveSdkProvider client={client}>
|
|
190
|
+
<App />
|
|
191
|
+
</HyveSdkProvider>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const hyve = useHyveSdk();
|
|
196
|
+
|
|
197
|
+
const result = await hyve.showAd("rewarded");
|
|
151
198
|
if (result.success) {
|
|
152
199
|
console.log("User watched the ad");
|
|
153
200
|
}
|
|
154
201
|
|
|
155
|
-
await
|
|
156
|
-
await
|
|
202
|
+
await hyve.showAd("interstitial"); // between levels
|
|
203
|
+
await hyve.showAd("preroll"); // game start
|
|
157
204
|
```
|
|
158
205
|
|
|
159
206
|
| Ad Type | Use Case |
|
|
@@ -171,14 +218,16 @@ The SDK automatically routes ad calls through the appropriate platform SDK (Craz
|
|
|
171
218
|
When running on CrazyGames, the SDK auto-initializes the CrazyGames SDK and routes ads through it. Use these additional lifecycle methods:
|
|
172
219
|
|
|
173
220
|
```ts
|
|
221
|
+
const hyve = useHyveSdk();
|
|
222
|
+
|
|
174
223
|
// Call when gameplay begins (required by CrazyGames policy)
|
|
175
|
-
await
|
|
224
|
+
await hyve.gameplayStart();
|
|
176
225
|
|
|
177
226
|
// Call when gameplay stops (paused, died, menu, etc.)
|
|
178
|
-
await
|
|
227
|
+
await hyve.gameplayStop();
|
|
179
228
|
|
|
180
229
|
// Trigger a celebration effect on the CrazyGames website
|
|
181
|
-
await
|
|
230
|
+
await hyve.happytime();
|
|
182
231
|
```
|
|
183
232
|
|
|
184
233
|
### Playgama
|
|
@@ -189,24 +238,32 @@ When running on Playgama, the SDK auto-initializes the Playgama Bridge and route
|
|
|
189
238
|
|
|
190
239
|
Billing supports web (Stripe) and native (In-App Purchases) — platform is detected automatically.
|
|
191
240
|
|
|
192
|
-
```
|
|
241
|
+
```tsx
|
|
193
242
|
const client = new HyveClient({
|
|
194
243
|
billing: {
|
|
195
244
|
stripePublishableKey: "pk_live_...",
|
|
196
245
|
},
|
|
197
246
|
});
|
|
198
247
|
|
|
199
|
-
|
|
200
|
-
|
|
248
|
+
<HyveSdkProvider client={client}>
|
|
249
|
+
<App />
|
|
250
|
+
</HyveSdkProvider>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
const hyve = useHyveSdk();
|
|
255
|
+
|
|
256
|
+
if (hyve.isBillingAvailable()) {
|
|
257
|
+
hyve.onPurchaseComplete((result) => {
|
|
201
258
|
console.log("Purchase successful:", result.transactionId);
|
|
202
259
|
});
|
|
203
260
|
|
|
204
|
-
|
|
261
|
+
hyve.onPurchaseError((result) => {
|
|
205
262
|
console.error("Purchase failed:", result.error?.message);
|
|
206
263
|
});
|
|
207
264
|
|
|
208
|
-
const products = await
|
|
209
|
-
await
|
|
265
|
+
const products = await hyve.getBillingProducts();
|
|
266
|
+
await hyve.purchaseProduct("price_1234");
|
|
210
267
|
}
|
|
211
268
|
```
|
|
212
269
|
|
|
@@ -294,7 +351,6 @@ localStorage.setItem("HYVE_SDK_LOG_LEVEL", "error,warn");
|
|
|
294
351
|
|
|
295
352
|
```ts
|
|
296
353
|
new HyveClient(config?: {
|
|
297
|
-
isDev?: boolean; // Override env detection (local testing only)
|
|
298
354
|
apiBaseUrl?: string; // Override API base URL
|
|
299
355
|
storageMode?: "cloud" | "local";
|
|
300
356
|
ads?: AdConfig;
|
|
@@ -310,6 +366,7 @@ new HyveClient(config?: {
|
|
|
310
366
|
| `getGameId()` | `string \| null` | Game ID from URL or JWT |
|
|
311
367
|
| `getSessionId()` | `string` | Unique session ID |
|
|
312
368
|
| `getJwtToken()` | `string \| null` | Raw JWT string |
|
|
369
|
+
| `getApiBaseUrl()` | `string` | Current API base URL |
|
|
313
370
|
| `isUserAuthenticated()` | `boolean` | Whether a user ID was extracted |
|
|
314
371
|
| `hasJwtToken()` | `boolean` | Whether a JWT is present |
|
|
315
372
|
| `logout()` | `void` | Clear auth state |
|
|
@@ -322,24 +379,26 @@ new HyveClient(config?: {
|
|
|
322
379
|
| `callApi<T>(endpoint, options?)` | `Promise<T>` | Authenticated fetch to the Hyve API |
|
|
323
380
|
| `getInventory()` | `Promise<Inventory>` | Get user inventory |
|
|
324
381
|
| `getInventoryItem(itemId)` | `Promise<InventoryItem>` | Get a specific inventory item |
|
|
382
|
+
| `getMachineRender(machineId)` | `Promise<string>` | Fetch rendered HTML for a project machine |
|
|
325
383
|
|
|
326
384
|
### Telemetry
|
|
327
385
|
|
|
328
386
|
| Method | Returns | Description |
|
|
329
387
|
|--------|---------|-------------|
|
|
330
|
-
| `sendTelemetry(location, category, action, subCategory?, subAction?, details?)` | `Promise<boolean>` | Send an analytics event |
|
|
388
|
+
| `sendTelemetry(location, category, action, subCategory?, subAction?, details?, platformId?)` | `Promise<boolean>` | Send an analytics event |
|
|
331
389
|
| `updateTelemetryConfig(config)` | `void` | Update telemetry settings at runtime |
|
|
332
390
|
|
|
333
391
|
### Storage
|
|
334
392
|
|
|
335
393
|
| Method | Returns | Description |
|
|
336
394
|
|--------|---------|-------------|
|
|
337
|
-
| `saveGameData(key, value, storage?)` | `Promise<SaveGameDataResponse>` | Save a single value |
|
|
338
|
-
| `batchSaveGameData(items, storage?)` | `Promise<
|
|
395
|
+
| `saveGameData(key, value, operation?, path?, storage?)` | `Promise<SaveGameDataResponse>` | Save a single value; optional atomic operation and nested path |
|
|
396
|
+
| `batchSaveGameData(items, storage?)` | `Promise<BatchSaveGameDataResponse>` | Save multiple values; each item may include an operation and path |
|
|
339
397
|
| `getGameData(key, storage?)` | `Promise<GameDataItem \| null>` | Get a single value |
|
|
340
398
|
| `getMultipleGameData(keys, storage?)` | `Promise<GameDataItem[]>` | Get multiple values |
|
|
341
399
|
| `deleteGameData(key, storage?)` | `Promise<boolean>` | Delete a single value |
|
|
342
|
-
| `deleteMultipleGameData(keys, storage?)` | `Promise<number>` | Delete multiple values |
|
|
400
|
+
| `deleteMultipleGameData(keys, storage?)` | `Promise<number>` | Delete multiple values; returns count |
|
|
401
|
+
| `getGameDataLeaderboard(params)` | `Promise<GameDataLeaderboardResponse>` | Fetch players ranked by a game data key |
|
|
343
402
|
| `configureStorage(mode)` | `void` | Set default storage mode |
|
|
344
403
|
| `getStorageMode()` | `"cloud" \| "local"` | Get current storage mode |
|
|
345
404
|
|