@series-inc/venus-sdk 2.2.0
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 +716 -0
- package/dist/AdsApi-BbMHVPYM.d.mts +692 -0
- package/dist/AdsApi-BbMHVPYM.d.ts +692 -0
- package/dist/chunk-7KKRTPDL.mjs +3135 -0
- package/dist/chunk-7KKRTPDL.mjs.map +1 -0
- package/dist/chunk-D4JRVWNC.mjs +82 -0
- package/dist/chunk-D4JRVWNC.mjs.map +1 -0
- package/dist/core-BTXL5C6G.mjs +3 -0
- package/dist/core-BTXL5C6G.mjs.map +1 -0
- package/dist/index.cjs +3205 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +702 -0
- package/dist/index.d.ts +702 -0
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -0
- package/dist/venus-api/index.cjs +8191 -0
- package/dist/venus-api/index.cjs.map +1 -0
- package/dist/venus-api/index.d.mts +15 -0
- package/dist/venus-api/index.d.ts +15 -0
- package/dist/venus-api/index.mjs +4961 -0
- package/dist/venus-api/index.mjs.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
# Venus SDK API
|
|
2
|
+
|
|
3
|
+
The core API package for the Venus SDK, providing comprehensive, type-safe interfaces for building H5 games and applications on the Venus platform.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install venus-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Architecture
|
|
12
|
+
|
|
13
|
+
The Venus SDK is built on a client-server RPC architecture:
|
|
14
|
+
|
|
15
|
+
- **Host Interface** - Main entry point grouping all APIs
|
|
16
|
+
- **RPC Transport** - Message-based communication with Venus platform
|
|
17
|
+
- **Mock Implementations** - Complete mock APIs for local development
|
|
18
|
+
- **Venus API** - Low-level platform interface
|
|
19
|
+
|
|
20
|
+
### Core Components
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { createHost, VenusAPI } from 'venus-sdk'
|
|
24
|
+
|
|
25
|
+
// Create Venus API instance
|
|
26
|
+
const venusApi = new VenusAPI()
|
|
27
|
+
await venusApi.initializeAsync()
|
|
28
|
+
|
|
29
|
+
// Create Host (false = remote, true = mock)
|
|
30
|
+
const host = createHost(venusApi, false)
|
|
31
|
+
await host.initialize()
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API Reference
|
|
35
|
+
|
|
36
|
+
### Simulation API
|
|
37
|
+
|
|
38
|
+
The Simulation API manages game state, recipe execution, and slot systems.
|
|
39
|
+
|
|
40
|
+
#### State Management
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Get current simulation state
|
|
44
|
+
const state = await host.simulation.getStateAsync(roomId?)
|
|
45
|
+
// Returns: { entities, inventory, currencies, timers, etc. }
|
|
46
|
+
|
|
47
|
+
// Get simulation configuration
|
|
48
|
+
const config = await host.simulation.getConfigAsync(roomId?)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Recipe Execution
|
|
52
|
+
|
|
53
|
+
Recipes are server-authoritative game actions (crafting, battles, upgrades, etc.):
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Execute a recipe
|
|
57
|
+
const result = await host.simulation.executeRecipeAsync(
|
|
58
|
+
'craft_sword',
|
|
59
|
+
{ materials: ['iron', 'wood'] },
|
|
60
|
+
{ skipNotification: false }
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
// Execute a scoped recipe (entity-specific)
|
|
64
|
+
const result = await host.simulation.executeScopedRecipeAsync(
|
|
65
|
+
'upgrade_weapon',
|
|
66
|
+
'sword_123',
|
|
67
|
+
{ level: 5 }
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
// Get active recipe runs (for time-based recipes)
|
|
71
|
+
const runs = await host.simulation.getActiveRunsAsync()
|
|
72
|
+
|
|
73
|
+
// Collect completed recipe
|
|
74
|
+
const result = await host.simulation.collectRecipeAsync(runId)
|
|
75
|
+
|
|
76
|
+
// Trigger recipe chain
|
|
77
|
+
await host.simulation.triggerRecipeChainAsync('battle_complete')
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### Recipe Requirements
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// Check requirements for a single recipe
|
|
84
|
+
const requirements = await host.simulation.getRecipeRequirementsAsync({
|
|
85
|
+
recipeId: 'craft_sword',
|
|
86
|
+
entity: 'player',
|
|
87
|
+
amount: 1
|
|
88
|
+
})
|
|
89
|
+
// Returns: { canAfford, costs, rewards }
|
|
90
|
+
|
|
91
|
+
// Batch check multiple recipes
|
|
92
|
+
const results = await host.simulation.getBatchRecipeRequirementsAsync([
|
|
93
|
+
{ recipeId: 'craft_sword', amount: 1 },
|
|
94
|
+
{ recipeId: 'craft_shield', amount: 2 }
|
|
95
|
+
])
|
|
96
|
+
|
|
97
|
+
// Get available recipes
|
|
98
|
+
const recipes = await host.simulation.getAvailableRecipesAsync({
|
|
99
|
+
roomId: 'room_123',
|
|
100
|
+
includeActorRecipes: true
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### Slot Management
|
|
105
|
+
|
|
106
|
+
Slots represent equipment, loadouts, teams, or any item container system:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// Get all slot containers
|
|
110
|
+
const containers = await host.simulation.getSlotContainersAsync()
|
|
111
|
+
// Returns: [{ id: 'equipment', slots: [...] }, { id: 'team', slots: [...] }]
|
|
112
|
+
|
|
113
|
+
// Get slot assignments for a container
|
|
114
|
+
const assignments = await host.simulation.getSlotAssignmentsAsync('equipment')
|
|
115
|
+
// Returns: [{ slotId: 'weapon', itemId: 'sword_123' }, ...]
|
|
116
|
+
|
|
117
|
+
// Assign item to slot
|
|
118
|
+
await host.simulation.assignItemToSlotAsync('equipment', 'weapon', 'sword_123')
|
|
119
|
+
|
|
120
|
+
// Remove item from slot
|
|
121
|
+
await host.simulation.removeItemFromSlotAsync('equipment', 'weapon')
|
|
122
|
+
|
|
123
|
+
// Get available items for a slot
|
|
124
|
+
const items = await host.simulation.getAvailableItemsAsync('equipment', 'weapon')
|
|
125
|
+
|
|
126
|
+
// Preview power calculation before assignment
|
|
127
|
+
const preview = await host.simulation.calculatePowerPreviewAsync(
|
|
128
|
+
'equipment',
|
|
129
|
+
'weapon',
|
|
130
|
+
'sword_456'
|
|
131
|
+
)
|
|
132
|
+
// Returns: { currentPower: 100, newPower: 150, delta: +50 }
|
|
133
|
+
|
|
134
|
+
// Validate slot assignment
|
|
135
|
+
const valid = await host.simulation.validateSlotAssignmentAsync(
|
|
136
|
+
'equipment',
|
|
137
|
+
'weapon',
|
|
138
|
+
'shield_123' // Wrong type
|
|
139
|
+
)
|
|
140
|
+
// Returns: { valid: false, reason: 'Type mismatch' }
|
|
141
|
+
|
|
142
|
+
// Batch operations (atomic)
|
|
143
|
+
await host.simulation.executeBatchOperationsAsync([
|
|
144
|
+
{ type: 'assign', containerId: 'equipment', slotId: 'weapon', itemId: 'sword' },
|
|
145
|
+
{ type: 'assign', containerId: 'equipment', slotId: 'armor', itemId: 'plate' },
|
|
146
|
+
{ type: 'remove', containerId: 'equipment', slotId: 'boots' }
|
|
147
|
+
], false) // false = execute, true = validate only
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Field Resolution & Metadata
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Resolve dynamic field values
|
|
154
|
+
const value = await host.simulation.resolveFieldValueAsync(
|
|
155
|
+
'player_123',
|
|
156
|
+
'stats.power',
|
|
157
|
+
'player'
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
// Get entity metadata
|
|
161
|
+
const metadata = await host.simulation.getEntityMetadataAsync('sword_123')
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Utility Methods
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// Sum stat contributions
|
|
168
|
+
const totalPower = host.simulation.sumContributions(
|
|
169
|
+
[{ power: 10 }, { power: 20 }, { power: 15 }],
|
|
170
|
+
'power'
|
|
171
|
+
)
|
|
172
|
+
// Returns: 45
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### Storage API
|
|
178
|
+
|
|
179
|
+
Three-tier storage system with different data scopes:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// Device Cache - persists across all apps for the device
|
|
183
|
+
await host.deviceCache.set('lastUserId', '12345')
|
|
184
|
+
const userId = await host.deviceCache.get('lastUserId')
|
|
185
|
+
|
|
186
|
+
// App Storage - app-specific persistent storage
|
|
187
|
+
await host.appStorage.set('highScore', 1000)
|
|
188
|
+
await host.appStorage.set('playerData', { level: 5, gold: 1000 })
|
|
189
|
+
|
|
190
|
+
// Global Storage - shared across all apps for the user
|
|
191
|
+
await host.globalStorage.set('preferences', { theme: 'dark' })
|
|
192
|
+
|
|
193
|
+
// All storage APIs support:
|
|
194
|
+
const value = await storage.get(key, defaultValue?)
|
|
195
|
+
await storage.set(key, value)
|
|
196
|
+
await storage.remove(key)
|
|
197
|
+
await storage.clear()
|
|
198
|
+
const count = await storage.length()
|
|
199
|
+
const keyName = await storage.key(index)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### Profile API
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// Get current user profile
|
|
208
|
+
const profile = await host.profile.getCurrentProfile()
|
|
209
|
+
// Returns: { id, name, username }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### Ads API
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// Check ad readiness
|
|
218
|
+
const interstitialReady = await host.ads.isInterstitialReady()
|
|
219
|
+
const rewardedReady = await host.ads.isRewardedReady()
|
|
220
|
+
|
|
221
|
+
// Show interstitial ad
|
|
222
|
+
await host.ads.showInterstitial()
|
|
223
|
+
|
|
224
|
+
// Show rewarded video ad
|
|
225
|
+
const watched = await host.ads.showRewarded()
|
|
226
|
+
if (watched) {
|
|
227
|
+
// User watched the full video, grant reward
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### Haptics API
|
|
234
|
+
|
|
235
|
+
Trigger haptic feedback on supported devices:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// Available haptic types: 'light', 'medium', 'heavy', 'success', 'warning', 'error'
|
|
239
|
+
await host.haptics.trigger('success')
|
|
240
|
+
await host.haptics.trigger('warning')
|
|
241
|
+
await host.haptics.trigger('heavy')
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### Popups API
|
|
247
|
+
|
|
248
|
+
Display native-style UI popups:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
// Toast messages
|
|
252
|
+
await host.popups.showToast('Game saved!', {
|
|
253
|
+
duration: 3000,
|
|
254
|
+
variant: 'success',
|
|
255
|
+
action: { label: 'Undo' }
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
// Alert dialog
|
|
259
|
+
await host.popups.showAlert({
|
|
260
|
+
title: 'Warning',
|
|
261
|
+
message: 'This action cannot be undone',
|
|
262
|
+
buttonText: 'OK'
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
// Confirm dialog
|
|
266
|
+
const confirmed = await host.popups.showConfirm({
|
|
267
|
+
title: 'Delete Item',
|
|
268
|
+
message: 'Are you sure you want to delete this item?',
|
|
269
|
+
confirmText: 'Delete',
|
|
270
|
+
cancelText: 'Cancel'
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
if (confirmed) {
|
|
274
|
+
// User confirmed
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Action sheet
|
|
278
|
+
const selected = await host.popups.showActionSheet({
|
|
279
|
+
title: 'Choose Action',
|
|
280
|
+
options: [
|
|
281
|
+
{ id: 'edit', label: 'Edit', variant: 'default' },
|
|
282
|
+
{ id: 'share', label: 'Share', variant: 'default' },
|
|
283
|
+
{ id: 'delete', label: 'Delete', variant: 'destructive' }
|
|
284
|
+
],
|
|
285
|
+
cancelText: 'Cancel'
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
if (selected === 'delete') {
|
|
289
|
+
// User selected delete
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
### Navigation API
|
|
296
|
+
|
|
297
|
+
Stack-based navigation system:
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// Get current stack information
|
|
301
|
+
const stack = await host.navigation.getStackInfo()
|
|
302
|
+
// Returns: { depth, currentApp, history }
|
|
303
|
+
|
|
304
|
+
// Push new app to stack
|
|
305
|
+
await host.navigation.push({
|
|
306
|
+
appId: 'bird-flap',
|
|
307
|
+
context: { level: 5, difficulty: 'hard' }
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
// Pop from stack (returns to previous app)
|
|
311
|
+
await host.navigation.pop()
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
### Post API
|
|
317
|
+
|
|
318
|
+
Social interaction APIs for posts:
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
// Get post interaction data
|
|
322
|
+
const interactions = await host.post.getInteractions()
|
|
323
|
+
// Returns: { postId, isLiked, isFollowing, likeCount, commentCount }
|
|
324
|
+
|
|
325
|
+
// Toggle like
|
|
326
|
+
await host.post.toggleLike()
|
|
327
|
+
|
|
328
|
+
// Toggle follow
|
|
329
|
+
await host.post.toggleFollow()
|
|
330
|
+
|
|
331
|
+
// Open comments UI
|
|
332
|
+
await host.post.openComments()
|
|
333
|
+
|
|
334
|
+
// Share post
|
|
335
|
+
await host.post.share({
|
|
336
|
+
message: 'Check this out!',
|
|
337
|
+
recipientIds: ['user1', 'user2']
|
|
338
|
+
})
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
### AI API
|
|
344
|
+
|
|
345
|
+
LLM integration for chat completions:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// Get available models
|
|
349
|
+
const models = await host.ai.getAvailableModels()
|
|
350
|
+
// Returns: ['gpt-4', 'gpt-3.5-turbo', 'claude-3-opus', ...]
|
|
351
|
+
|
|
352
|
+
// Chat completion
|
|
353
|
+
const response = await host.ai.chatCompletion({
|
|
354
|
+
messages: [
|
|
355
|
+
{ role: 'system', content: 'You are a helpful game assistant' },
|
|
356
|
+
{ role: 'user', content: 'What is the best strategy for this level?' }
|
|
357
|
+
],
|
|
358
|
+
model: 'gpt-4',
|
|
359
|
+
temperature: 0.7,
|
|
360
|
+
max_tokens: 500
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
console.log(response.choices[0].message.content)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
### Analytics API
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
// Log custom event
|
|
372
|
+
await host.analytics.logEvent('level_complete', {
|
|
373
|
+
level: 5,
|
|
374
|
+
score: 1000,
|
|
375
|
+
timeElapsed: 120
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
// Set user properties
|
|
379
|
+
await host.analytics.setUserProperty('vip_status', 'gold')
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### Avatar 3D API
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
// Get current avatar configuration
|
|
388
|
+
const avatar = await host.avatar3d.get()
|
|
389
|
+
|
|
390
|
+
// Show avatar editor
|
|
391
|
+
const result = await host.avatar3d.showEditor({
|
|
392
|
+
allowSave: true,
|
|
393
|
+
enableSharing: true
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
if (result.saved) {
|
|
397
|
+
console.log('Avatar updated:', result.avatarId)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Delete avatar
|
|
401
|
+
await host.avatar3d.delete()
|
|
402
|
+
|
|
403
|
+
// Get shared avatar
|
|
404
|
+
const sharedAvatar = await host.avatar3d.getSharedAvatar('avatar_123')
|
|
405
|
+
|
|
406
|
+
// Download avatar manifest
|
|
407
|
+
const manifest = await host.avatar3d.downloadManifest('avatar_123')
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
### Rooms API
|
|
413
|
+
|
|
414
|
+
Multi-user room management:
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
// Get current room
|
|
418
|
+
const room = await host.rooms.getCurrentRoom()
|
|
419
|
+
// Returns: { id, name, participants, metadata }
|
|
420
|
+
|
|
421
|
+
// Join room
|
|
422
|
+
await host.rooms.join('room_123')
|
|
423
|
+
|
|
424
|
+
// Leave room
|
|
425
|
+
await host.rooms.leave()
|
|
426
|
+
|
|
427
|
+
// Send room message
|
|
428
|
+
await host.rooms.sendMessage({
|
|
429
|
+
type: 'game_action',
|
|
430
|
+
data: { action: 'move', x: 10, y: 20 }
|
|
431
|
+
})
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
### Notifications API
|
|
437
|
+
|
|
438
|
+
Local push notifications:
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
// Schedule notification
|
|
442
|
+
await host.notifications.schedule({
|
|
443
|
+
id: 'energy_full',
|
|
444
|
+
title: 'Energy Restored!',
|
|
445
|
+
body: 'Your energy is now full. Come back to play!',
|
|
446
|
+
trigger: { type: 'time', seconds: 3600 } // 1 hour
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
// Cancel notification
|
|
450
|
+
await host.notifications.cancel('energy_full')
|
|
451
|
+
|
|
452
|
+
// Get all scheduled notifications
|
|
453
|
+
const scheduled = await host.notifications.getAllScheduled()
|
|
454
|
+
|
|
455
|
+
// Check if notifications are enabled
|
|
456
|
+
const enabled = await host.notifications.isEnabled()
|
|
457
|
+
|
|
458
|
+
// Enable/disable notifications
|
|
459
|
+
await host.notifications.setEnabled(true)
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
### Time API
|
|
465
|
+
|
|
466
|
+
Server time synchronization and formatting:
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
// Get server time
|
|
470
|
+
const serverTime = await host.time.getServerTime()
|
|
471
|
+
// Returns: { timestamp, timezone, formatted }
|
|
472
|
+
|
|
473
|
+
// Format time with locale
|
|
474
|
+
const formatted = host.time.format(Date.now(), {
|
|
475
|
+
locale: 'en-US',
|
|
476
|
+
format: 'full' // 'full', 'long', 'medium', 'short'
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
// Format number with locale
|
|
480
|
+
const formatted = host.time.formatNumber(1234567.89, {
|
|
481
|
+
locale: 'en-US',
|
|
482
|
+
style: 'currency',
|
|
483
|
+
currency: 'USD'
|
|
484
|
+
})
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
### CDN API
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
// Get CDN URL for an asset
|
|
493
|
+
const url = await host.cdn.getAssetUrl('images/logo.png')
|
|
494
|
+
|
|
495
|
+
// Upload to CDN
|
|
496
|
+
const uploadUrl = await host.cdn.upload(file)
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
### Features API
|
|
502
|
+
|
|
503
|
+
Feature flags, experiments, and A/B testing:
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
// Get feature flag value
|
|
507
|
+
const enabled = await host.features.getFeatureFlag('new_ui_enabled')
|
|
508
|
+
|
|
509
|
+
// Get feature gate (boolean flag)
|
|
510
|
+
const canAccess = await host.features.getFeatureGate('beta_features')
|
|
511
|
+
|
|
512
|
+
// Get experiment variant
|
|
513
|
+
const experiment = await host.features.getExperiment('checkout_flow')
|
|
514
|
+
// Returns: { variant: 'control' | 'variant_a' | 'variant_b', ... }
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
### IAP API
|
|
520
|
+
|
|
521
|
+
In-app purchases and virtual currency:
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
// Get wallet balance
|
|
525
|
+
const wallet = await host.iap.getWallet()
|
|
526
|
+
// Returns: { coins: 1000, gems: 50 }
|
|
527
|
+
|
|
528
|
+
// Spend currency
|
|
529
|
+
const result = await host.iap.spendCurrency('coins', 100)
|
|
530
|
+
if (result.success) {
|
|
531
|
+
console.log('Purchase successful')
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Listen for wallet updates
|
|
535
|
+
host.iap.onWalletUpdate((wallet) => {
|
|
536
|
+
console.log('Wallet updated:', wallet)
|
|
537
|
+
})
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
### Lifecycle API
|
|
543
|
+
|
|
544
|
+
App lifecycle event handlers:
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
// Register lifecycle callbacks
|
|
548
|
+
host.lifecycle.onReady(() => {
|
|
549
|
+
console.log('App ready')
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
host.lifecycle.onShow((context) => {
|
|
553
|
+
console.log('App shown', context.hudInsets)
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
host.lifecycle.onPlay((context) => {
|
|
557
|
+
console.log('App playing', context.hudInsets)
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
host.lifecycle.onPause(() => {
|
|
561
|
+
console.log('App paused')
|
|
562
|
+
})
|
|
563
|
+
|
|
564
|
+
host.lifecycle.onResume(() => {
|
|
565
|
+
console.log('App resumed')
|
|
566
|
+
})
|
|
567
|
+
|
|
568
|
+
host.lifecycle.onHidden(() => {
|
|
569
|
+
console.log('App hidden')
|
|
570
|
+
})
|
|
571
|
+
|
|
572
|
+
host.lifecycle.onQuit(() => {
|
|
573
|
+
console.log('App quitting')
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
// Quit the app
|
|
577
|
+
await host.lifecycle.quit()
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
### Logging API
|
|
583
|
+
|
|
584
|
+
```typescript
|
|
585
|
+
// Log messages
|
|
586
|
+
host.logging.log('Info message', { data: 'value' })
|
|
587
|
+
host.logging.error('Error message', error)
|
|
588
|
+
host.logging.debug('Debug info')
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## Mock Mode
|
|
594
|
+
|
|
595
|
+
All APIs have complete mock implementations for local development:
|
|
596
|
+
|
|
597
|
+
```typescript
|
|
598
|
+
import { createHost, VenusAPI } from 'venus-sdk'
|
|
599
|
+
|
|
600
|
+
const venusApi = new VenusAPI()
|
|
601
|
+
await venusApi.initializeAsync({ mock: true })
|
|
602
|
+
|
|
603
|
+
const host = createHost(venusApi, true) // true = mock mode
|
|
604
|
+
await host.initialize()
|
|
605
|
+
|
|
606
|
+
// All APIs work the same, but with simulated responses
|
|
607
|
+
const state = await host.simulation.getStateAsync()
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### Custom Mock Data
|
|
611
|
+
|
|
612
|
+
```typescript
|
|
613
|
+
await venusApi.initializeAsync({
|
|
614
|
+
mock: {
|
|
615
|
+
simulation: {
|
|
616
|
+
state: { customData: 'value' }
|
|
617
|
+
},
|
|
618
|
+
profile: {
|
|
619
|
+
name: 'Test User',
|
|
620
|
+
username: 'test_user'
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
})
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
## RPC Transport
|
|
629
|
+
|
|
630
|
+
The SDK uses an RPC (Remote Procedure Call) architecture for communication:
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
import { RpcClient, VenusTransport } from 'venus-sdk'
|
|
634
|
+
|
|
635
|
+
// Low-level RPC client
|
|
636
|
+
const transport = new VenusTransport()
|
|
637
|
+
const rpcClient = new RpcClient(transport)
|
|
638
|
+
|
|
639
|
+
// Send request
|
|
640
|
+
const response = await rpcClient.request({
|
|
641
|
+
method: 'simulation.getState',
|
|
642
|
+
params: { roomId: 'room_123' }
|
|
643
|
+
})
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## Build Configuration
|
|
649
|
+
|
|
650
|
+
The package is built with `tsup` and provides multiple module formats:
|
|
651
|
+
|
|
652
|
+
```json
|
|
653
|
+
{
|
|
654
|
+
"main": "./dist/index.cjs",
|
|
655
|
+
"module": "./dist/index.mjs",
|
|
656
|
+
"types": "./dist/index.d.ts",
|
|
657
|
+
"exports": {
|
|
658
|
+
".": {
|
|
659
|
+
"types": "./dist/index.d.ts",
|
|
660
|
+
"import": "./dist/index.mjs",
|
|
661
|
+
"require": "./dist/index.cjs"
|
|
662
|
+
},
|
|
663
|
+
"./api": {
|
|
664
|
+
"types": "./dist/venus-api/index.d.ts",
|
|
665
|
+
"import": "./dist/venus-api/index.mjs",
|
|
666
|
+
"require": "./dist/venus-api/index.cjs"
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
## TypeScript Configuration
|
|
675
|
+
|
|
676
|
+
The package uses TypeScript 5.9+ with strict type checking:
|
|
677
|
+
|
|
678
|
+
```json
|
|
679
|
+
{
|
|
680
|
+
"compilerOptions": {
|
|
681
|
+
"strict": true,
|
|
682
|
+
"target": "ES2020",
|
|
683
|
+
"module": "ESNext",
|
|
684
|
+
"moduleResolution": "bundler"
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## Testing
|
|
692
|
+
|
|
693
|
+
```bash
|
|
694
|
+
# Run unit tests
|
|
695
|
+
npm test
|
|
696
|
+
|
|
697
|
+
# Run tests in watch mode
|
|
698
|
+
npm test -- --watch
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
Tests are written using Jest with JSDOM environment for browser API simulation.
|
|
702
|
+
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
## License
|
|
706
|
+
|
|
707
|
+
MIT
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
## Related
|
|
712
|
+
|
|
713
|
+
- [Main Repository](https://github.com/SeriesAI/venus-sdk)
|
|
714
|
+
- [npm Package](https://www.npmjs.com/package/venus-sdk)
|
|
715
|
+
- [Issue Tracker](https://github.com/SeriesAI/venus-sdk/issues)
|
|
716
|
+
|