@series-inc/venus-sdk 3.0.6 → 3.1.0-beta.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.
Files changed (39) hide show
  1. package/README.md +1180 -14
  2. package/dist/{AdsApi-CIXV8I_p.d.mts → AdsApi-meVfUcZy.d.mts} +164 -355
  3. package/dist/{AdsApi-CIXV8I_p.d.ts → AdsApi-meVfUcZy.d.ts} +164 -355
  4. package/dist/chunk-2PDL7CQK.mjs +26 -0
  5. package/dist/chunk-2PDL7CQK.mjs.map +1 -0
  6. package/dist/{chunk-LBJFUHOH.mjs → chunk-EMVTVSGL.mjs} +1471 -737
  7. package/dist/chunk-EMVTVSGL.mjs.map +1 -0
  8. package/dist/chunk-IZLOB7DV.mjs +343 -0
  9. package/dist/chunk-IZLOB7DV.mjs.map +1 -0
  10. package/dist/{chunk-MWUS3A7C.mjs → chunk-QABXMFND.mjs} +3 -7
  11. package/dist/chunk-QABXMFND.mjs.map +1 -0
  12. package/dist/core-5JLON75E.mjs +4 -0
  13. package/dist/{core-RDMPQV6U.mjs.map → core-5JLON75E.mjs.map} +1 -1
  14. package/dist/index.cjs +1883 -778
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.mts +113 -61
  17. package/dist/index.d.ts +113 -61
  18. package/dist/index.mjs +8 -2
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/venus-api/index.cjs +1806 -748
  21. package/dist/venus-api/index.cjs.map +1 -1
  22. package/dist/venus-api/index.d.mts +2 -2
  23. package/dist/venus-api/index.d.ts +2 -2
  24. package/dist/venus-api/index.mjs +311 -3
  25. package/dist/venus-api/index.mjs.map +1 -1
  26. package/dist/vite/index.cjs +534 -0
  27. package/dist/vite/index.cjs.map +1 -0
  28. package/dist/vite/index.mjs +527 -0
  29. package/dist/vite/index.mjs.map +1 -0
  30. package/dist/webview/index.cjs +346 -0
  31. package/dist/webview/index.cjs.map +1 -0
  32. package/dist/webview/index.d.mts +17 -0
  33. package/dist/webview/index.d.ts +17 -0
  34. package/dist/webview/index.mjs +4 -0
  35. package/dist/webview/index.mjs.map +1 -0
  36. package/package.json +19 -1
  37. package/dist/chunk-LBJFUHOH.mjs.map +0 -1
  38. package/dist/chunk-MWUS3A7C.mjs.map +0 -1
  39. package/dist/core-RDMPQV6U.mjs +0 -3
package/README.md CHANGED
@@ -1,21 +1,23 @@
1
1
  # Venus SDK API
2
2
 
3
- Build connected HTML5 games that integrate deeply with the Venus platform. This package provides the client SDK used by hosted games as well as the local mock environment for development.
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
4
 
5
- ## Highlights
5
+ ## Installation
6
6
 
7
- - Typed APIs for Venus platform services (simulation, rooms, analytics, ads, and more)
8
- - Host-aware tooling including lifecycle hooks, safe-area utilities, and asset loading helpers
7
+ ```bash
8
+ npm install venus-sdk
9
+ ```
9
10
 
10
- ## Quick Start
11
+ ## Architecture
11
12
 
12
- ### Installation
13
+ The Venus SDK is built on a client-server RPC architecture:
13
14
 
14
- ```bash
15
- npm install @series-inc/venus-sdk@latest
16
- ```
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
17
19
 
18
- ### Initialize
20
+ ### Usage
19
21
 
20
22
  ```typescript
21
23
  import { default as VenusAPI } from '@series-inc/venus-sdk/api'
@@ -24,10 +26,1174 @@ import { default as VenusAPI } from '@series-inc/venus-sdk/api'
24
26
  await VenusAPI.initializeAsync()
25
27
  ```
26
28
 
27
- ## Documentation
29
+ ## API Overview
30
+
31
+ ### Profile API
32
+
33
+ ```typescript
34
+ // Get current user profile (synchronous)
35
+ const profile = VenusAPI.profile.getCurrentProfile()
36
+ console.log(profile.name, profile.username)
37
+ ```
38
+ ---
39
+
40
+ ### Safe Area & HUD Insets
41
+
42
+ ```typescript
43
+ // Static safe area from initialization (baseline padding)
44
+ const safeArea = VenusAPI.config.ui.safeArea
45
+ layout.style.paddingTop = `${safeArea.top}px`
46
+ layout.style.paddingBottom = `${safeArea.bottom}px`
47
+
48
+ // Dynamic HUD insets arrive with lifecycle events
49
+ VenusAPI.lifecycle.onShow(({ hudInsets }) => {
50
+ applyInsets(hudInsets, 'preview')
51
+ })
52
+
53
+ VenusAPI.lifecycle.onPlay(({ hudInsets }) => {
54
+ applyInsets(hudInsets, 'fullscreen')
55
+ })
56
+
57
+ function applyInsets(insets, mode) {
58
+ // Use whichever inset is larger to avoid overlap with host UI
59
+ const top = Math.max(VenusAPI.config.ui.safeArea.top, insets.top)
60
+ canvas.style.paddingTop = `${top}px`
61
+ canvas.dataset.mode = mode
62
+ }
63
+ ```
64
+
65
+ `safeArea` provides a static baseline defined at initialization. `hudInsets` reflect the live host UI chrome and differ between preview (`onShow`) and fullscreen (`onPlay`) contexts.
66
+
67
+ ---
68
+
69
+ ### Ads API
70
+
71
+ ```typescript
72
+ // Check if rewarded ad is ready
73
+ const rewardedReady = await VenusAPI.ads.isRewardedAdReadyAsync()
74
+
75
+ // Show interstitial ad
76
+ const interstitialShown = await VenusAPI.ads.showInterstitialAd()
77
+ if (interstitialShown) {
78
+ // Interstitial ad was displayed
79
+ }
80
+
81
+ // Show rewarded video ad
82
+ const rewardEarned = await VenusAPI.ads.showRewardedAdAsync()
83
+ if (rewardEarned) {
84
+ // User watched the full video and earned reward
85
+ }
86
+ ```
87
+ ---
88
+
89
+ ### Haptics API
90
+
91
+ ```typescript
92
+ // Trigger haptic feedback
93
+ await VenusAPI.haptics.triggerHapticAsync('success')
94
+ await VenusAPI.haptics.triggerHapticAsync('warning')
95
+ await VenusAPI.haptics.triggerHapticAsync('error')
96
+ await VenusAPI.haptics.triggerHapticAsync('light')
97
+ await VenusAPI.haptics.triggerHapticAsync('medium')
98
+ await VenusAPI.haptics.triggerHapticAsync('heavy')
99
+ ```
100
+ ---
101
+
102
+ ### Local Notifications API
103
+
104
+ ```typescript
105
+ // Schedule a delayed notification (minimal - required params only)
106
+ const id = await VenusApi.notifications.scheduleAsync(
107
+ 'Notification Title',
108
+ 'Notification Body',
109
+ 60 // Delay in seconds
110
+ )
111
+
112
+ // Schedule with optional notification ID
113
+ const id = await VenusApi.notifications.scheduleAsync(
114
+ 'Notification Title',
115
+ 'Notification Body',
116
+ 60,
117
+ 'custom-notification-id'
118
+ )
119
+
120
+ // Schedule with all optional settings
121
+ const id = await VenusApi.notifications.scheduleAsync(
122
+ 'Notification Title',
123
+ 'Notification Body',
124
+ 60,
125
+ 'custom-notification-id',
126
+ {
127
+ priority: 100, // 0-100, default 50
128
+ groupId: 'reminders', // Group related notifications
129
+ payload: { key: 'value' } // Custom data
130
+ }
131
+ )
132
+
133
+ // Cancel a notification
134
+ await VenusApi.notifications.cancelNotification(notificationId)
135
+
136
+ // Get all scheduled notifications
137
+ await VenusApi.notifications.getAllScheduledLocalNotifications()
138
+ ```
139
+ ---
140
+
141
+ ### Loader API
142
+
143
+ The preloader is opt-in by default. In order to opt in, you must add
144
+ ```typescript
145
+ await VenusAPI.initializeAsync({ usePreloader: true })
146
+ ```
147
+
148
+ ```typescript
149
+ // Activating and dismissing the preloader
150
+ await VenusApi.preloader.showLoadScreen()
151
+ await VenusApi.preloader.hideLoadScreen()
152
+ ```
153
+ ---
154
+
155
+ ### Custom Funnel Events API
156
+
157
+ ```typescript
158
+ // Record a custom analytics event
159
+ await VenusApi.analytics.recordCustomEvent('level_completed', {
160
+ level: 5,
161
+ score: 1250,
162
+ time: 45.2
163
+ })
164
+
165
+ // Track funnel step with optional funnel name
166
+ await VenusApi.analytics.trackFunnelStep(1, 'tutorial_started', 'onboarding')
167
+ await VenusApi.analytics.trackFunnelStep(2, 'tutorial_completed', 'onboarding')
168
+ ```
169
+ ---
170
+
171
+ ### IAP API
172
+
173
+ ```typescript
174
+ // get VBucks/Hard Currency balance
175
+ await VenusApi.iap.getHardCurrencyBalance()
176
+ // Spend VBucks/Hard Currency
177
+ await VenusApi.iap.spendCurrency('yourProductID', 3)
178
+ // Open Venus Store
179
+ await VenusApi.iap.openStore()
180
+ // Get Currency Icon
181
+ await VenusApi.iap.getCurrencyIcon()
182
+ ```
183
+ ---
184
+
185
+ ### Saves API
186
+
187
+ ```typescript
188
+ // Get an item from storage
189
+ await VenusApi.storage.getItem('playerData')
190
+ // Set an item in storage
191
+ await VenusApi.storage.setItem('playerData', JSON.stringify({ level: 10 }))
192
+ // Remove an item from storage
193
+ await VenusApi.storage.removeItem('playerData')
194
+ // Get storage length
195
+ await VenusApi.storage.length()
196
+ // Get key at specific index
197
+ await VenusApi.storage.key(0)
198
+ // Clear all items from storage
199
+ await VenusApi.storage.clear()
200
+ // Set multiple items at once
201
+ await VenusApi.storage.setMultipleItems([
202
+ { key: 'playerData', value: JSON.stringify({ level: 10 }) },
203
+ { key: 'settings', value: JSON.stringify({ sound: true }) }
204
+ ])
205
+ // Remove multiple items at once
206
+ await VenusApi.storage.removeMultipleItems(['playerData', 'settings'])
207
+ // Get all items from storage
208
+ await VenusApi.storage.getAllItems()
209
+ ```
210
+ ---
211
+
212
+ ### LLM API
213
+
214
+ ```typescript
215
+ // Request chat completion from AI model
216
+ const response = await VenusApi.ai.requestChatCompletionAsync({
217
+ model: 'chatGPT',
218
+ messages: [
219
+ {
220
+ role: 'user',
221
+ content: 'What is the best strategy for this level?'
222
+ }
223
+ ]
224
+ })
225
+
226
+ // Get available completion models
227
+ const models = await VenusApi.ai.getAvailableCompletionModels()
228
+ ```
229
+
230
+ ### Simulation API
231
+
232
+ The Simulation API manages game state, recipe execution, and slot systems.
233
+
234
+ #### State Management
235
+
236
+ ```typescript
237
+ // Get current simulation state
238
+ const state = await VenusAPI.simulation.getStateAsync(roomId?)
239
+ // Returns: { entities, inventory, currencies, timers, etc. }
240
+
241
+ // Get simulation configuration
242
+ const config = await VenusAPI.simulation.getConfigAsync(roomId?)
243
+ ```
244
+
245
+ #### Recipe Execution
246
+
247
+ Recipes are server-authoritative game actions (crafting, battles, upgrades, etc.):
248
+
249
+ ```typescript
250
+ // Execute a recipe
251
+ const result = await VenusAPI.simulation.executeRecipeAsync(
252
+ 'craft_sword',
253
+ { materials: ['iron', 'wood'] },
254
+ { skipNotification: false }
255
+ )
256
+
257
+ // Execute a scoped recipe (entity-specific)
258
+ const result = await VenusAPI.simulation.executeScopedRecipeAsync(
259
+ 'upgrade_weapon',
260
+ 'sword_123',
261
+ { level: 5 }
262
+ )
263
+
264
+ // Get active recipe runs (for time-based recipes)
265
+ const runs = await VenusAPI.simulation.getActiveRunsAsync()
266
+
267
+ // Collect completed recipe
268
+ const result = await VenusAPI.simulation.collectRecipeAsync(runId)
269
+
270
+ // Trigger recipe chain
271
+ await VenusAPI.simulation.triggerRecipeChainAsync('battle_complete')
272
+ ```
273
+
274
+ #### Recipe Requirements
275
+
276
+ ```typescript
277
+ // Check requirements for a single recipe
278
+ const requirements = await VenusAPI.simulation.getRecipeRequirementsAsync(
279
+ 'craft_sword',
280
+ 'player',
281
+ 1
282
+ )
283
+ // Returns: { recipeId, entity, amount?, inputs, canAfford, disabled }
284
+
285
+ // Batch check multiple recipes
286
+ const results = await VenusAPI.simulation.getBatchRecipeRequirementsAsync([
287
+ { recipeId: 'craft_sword', batchAmount: 1 },
288
+ { recipeId: 'craft_shield', batchAmount: 2 }
289
+ ])
290
+ // Returns: { success, results, errors? }
291
+
292
+ // Get available recipes
293
+ const recipes = await VenusAPI.simulation.getAvailableRecipesAsync({
294
+ roomId: 'room_123',
295
+ includeActorRecipes: true
296
+ })
297
+ // Returns: { success, recipes }
298
+ ```
299
+
300
+ #### Slot Management
301
+
302
+ Slots represent equipment, loadouts, teams, or any item container system:
303
+
304
+ ```typescript
305
+ // Get all slot containers
306
+ const containers = await VenusAPI.simulation.getSlotContainersAsync()
307
+ // Returns: [{ id: 'equipment', slots: [...] }, { id: 'team', slots: [...] }]
308
+
309
+ // Get slot assignments for a container
310
+ const assignments = await VenusAPI.simulation.getSlotAssignmentsAsync('equipment')
311
+ // Returns: [{ slotId: 'weapon', itemId: 'sword_123' }, ...]
312
+
313
+ // Assign item to slot
314
+ await VenusAPI.simulation.assignItemToSlotAsync('equipment', 'weapon', 'sword_123')
315
+
316
+ // Remove item from slot
317
+ await VenusAPI.simulation.removeItemFromSlotAsync('equipment', 'weapon')
318
+
319
+ // Get available items for a slot
320
+ const items = await VenusAPI.simulation.getAvailableItemsAsync('equipment', 'weapon')
321
+
322
+ // Preview power calculation before assignment
323
+ const preview = await VenusAPI.simulation.calculatePowerPreviewAsync(
324
+ 'equipment',
325
+ 'weapon',
326
+ 'sword_456'
327
+ )
328
+ // Returns: { currentPower: 100, newPower: 150, delta: +50 }
329
+
330
+ // Validate slot assignment
331
+ const valid = await VenusAPI.simulation.validateSlotAssignmentAsync(
332
+ 'equipment',
333
+ 'weapon',
334
+ 'shield_123' // Wrong type
335
+ )
336
+ // Returns: { valid: false, reason: 'Type mismatch' }
337
+
338
+ // Batch operations (atomic)
339
+ await VenusAPI.simulation.executeBatchOperationsAsync([
340
+ { type: 'assign', containerId: 'equipment', slotId: 'weapon', itemId: 'sword' },
341
+ { type: 'assign', containerId: 'equipment', slotId: 'armor', itemId: 'plate' },
342
+ { type: 'remove', containerId: 'equipment', slotId: 'boots' }
343
+ ], false) // false = execute, true = validate only
344
+ ```
345
+
346
+ #### Field Resolution & Metadata
347
+
348
+ ```typescript
349
+ // Resolve dynamic field values
350
+ const value = await VenusAPI.simulation.resolveFieldValueAsync(
351
+ 'player_123',
352
+ 'stats.power',
353
+ 'player'
354
+ )
355
+
356
+ // Get entity metadata
357
+ const metadata = await VenusAPI.simulation.getEntityMetadataAsync('sword_123')
358
+ ```
359
+ ---
360
+
361
+ #### Utility Methods
362
+
363
+ ```typescript
364
+ // Sum stat contributions
365
+ const totalPower = VenusAPI.simulation.sumContributions(
366
+ [{ power: 10 }, { power: 20 }, { power: 15 }],
367
+ 'power'
368
+ )
369
+ // Returns: 45
370
+ ```
371
+
372
+ ---
373
+
374
+ ### Storage API
375
+
376
+ Three-tier storage system with different data scopes:
377
+
378
+ ```typescript
379
+ // Device Cache - persists across all apps for the device
380
+ await VenusAPI.deviceCache.setItem('lastUserId', '12345')
381
+ const userId = await VenusAPI.deviceCache.getItem('lastUserId')
382
+
383
+ // App Storage - app-specific persistent storage
384
+ await VenusAPI.appStorage.setItem('highScore', JSON.stringify(1000))
385
+ await VenusAPI.appStorage.setItem('playerData', JSON.stringify({ level: 5, gold: 1000 }))
386
+
387
+ // Global Storage - shared across all apps for the user
388
+ await VenusAPI.globalStorage.setItem('preferences', JSON.stringify({ theme: 'dark' }))
389
+
390
+ // All storage APIs support:
391
+ const value = await storage.getItem(key)
392
+ await storage.setItem(key, value)
393
+ await storage.removeItem(key)
394
+ await storage.clear()
395
+ const count = await storage.length()
396
+ const keyName = await storage.key(index)
397
+ ```
398
+
399
+ ---
400
+
401
+
402
+ ### Popups API
403
+
404
+ Display native-style UI popups:
405
+
406
+ ```typescript
407
+ // Toast messages
408
+ await VenusAPI.popups.showToast('Game saved!', {
409
+ duration: 3000,
410
+ variant: 'success',
411
+ action: { label: 'Undo' }
412
+ })
413
+
414
+ // Alert dialog
415
+ await VenusAPI.popups.showAlert(
416
+ 'Warning',
417
+ 'This action cannot be undone',
418
+ { buttonText: 'OK' }
419
+ )
420
+
421
+ // Confirm dialog
422
+ const confirmed = await VenusAPI.popups.showConfirm(
423
+ 'Delete Item',
424
+ 'Are you sure you want to delete this item?',
425
+ { confirmText: 'Delete', cancelText: 'Cancel' }
426
+ )
427
+
428
+ if (confirmed) {
429
+ // User confirmed
430
+ }
431
+
432
+ // Action sheet
433
+ const selected = await VenusAPI.popups.showActionSheet(
434
+ [
435
+ { id: 'edit', label: 'Edit' },
436
+ { id: 'share', label: 'Share' },
437
+ { id: 'delete', label: 'Delete' }
438
+ ],
439
+ {
440
+ title: 'Choose Action',
441
+ cancelButtonText: 'Cancel'
442
+ }
443
+ )
444
+
445
+ if (selected === 'delete') {
446
+ // User selected delete
447
+ }
448
+ ```
449
+
450
+ ---
451
+
452
+ ### Navigation API
453
+
454
+ Stack-based navigation system:
455
+
456
+ ```typescript
457
+ // Get current stack information (synchronous)
458
+ const stack = VenusAPI.navigation.getStackInfo()
459
+ // Returns: { isInStack, stackPosition, isTopOfStack, stackDepth, parentInstanceId }
460
+
461
+ // Push new app to stack
462
+ await VenusAPI.navigation.pushApp('bird-flap', {
463
+ contextData: { level: 5, difficulty: 'hard' }
464
+ })
465
+
466
+ // Pop from stack (returns to previous app)
467
+ await VenusAPI.navigation.popApp()
468
+ ```
469
+
470
+ ---
471
+
472
+ ### Post API
473
+
474
+ Social interaction APIs for posts:
475
+
476
+ ```typescript
477
+ // Get post interaction data
478
+ const postInfo = await VenusAPI.post.getPostInfo()
479
+ // Returns: { isLiked, isFollowing, likesCount, commentsCount }
480
+
481
+ // Toggle like
482
+ const likeResult = await VenusAPI.post.toggleLikeAsync()
483
+ // Returns: { isLiked, likesCount, action: 'liked' | 'unliked' }
484
+
485
+ // Toggle follow
486
+ const followResult = await VenusAPI.post.toggleFollowAsync()
487
+ // Returns: { isFollowing, action: 'followed' | 'unfollowed' }
488
+
489
+ // Open comments UI
490
+ const commentsResult = await VenusAPI.post.openCommentsAsync()
491
+ // Returns: { opened, commentsCount }
492
+
493
+ // Share post
494
+ const shareResult = await VenusAPI.post.sharePostAsync({
495
+ message: 'Check this out!',
496
+ title: 'My Post'
497
+ })
498
+ // Returns: { shared, platform, customMessage? }
499
+ ```
500
+
501
+ ---
502
+
503
+ ### Social API (BETA)
504
+
505
+ Share links and QR codes for challenges and UGC (user-generated content):
506
+
507
+ ```typescript
508
+ // Share a high score challenge - automatically opens share dialog!
509
+ const { shareUrl } = await VenusAPI.social.shareLinkAsync({
510
+ launchParams: {
511
+ challengeType: 'highscore',
512
+ scoreTobeat: '1500',
513
+ challengerId: VenusAPI.profile.getCurrentProfile().id
514
+ },
515
+ metadata: {
516
+ title: 'Beat my score!',
517
+ description: 'Can you beat 1500 points in Word Search?',
518
+ imageUrl: 'https://cdn.example.com/share-highscore.png'
519
+ }
520
+ })
521
+ // This function automatically triggers the share UI:
522
+ // - iOS/Android: Opens native share sheet
523
+ // - Web: Uses navigator.share() if available, otherwise copies to clipboard
524
+ // The returned shareUrl is the generated link that was shared
525
+
526
+ // Generate QR code for in-person challenges (does NOT open share dialog)
527
+ const { shareUrl, qrCode } = await VenusAPI.social.createQRCodeAsync({
528
+ launchParams: {
529
+ challengeType: 'daily',
530
+ dailyPuzzleId: '2024-11-04',
531
+ invitedBy: VenusAPI.profile.getCurrentProfile().username
532
+ },
533
+ metadata: {
534
+ title: 'Daily Challenge',
535
+ description: 'Scan to play today\'s puzzle with me!'
536
+ },
537
+ qrOptions: {
538
+ size: 512, // Size in pixels (default: 256)
539
+ margin: 4, // Margin in modules (default: 2)
540
+ format: 'png' // 'png' or 'svg'
541
+ }
542
+ })
543
+ // This only generates the QR code - you control how to display it
544
+
545
+ // Display the QR code in your UI
546
+ const img = document.createElement('img')
547
+ img.src = qrCode // Data URL (e.g., 'data:image/png;base64,...')
548
+ document.body.appendChild(img)
549
+
550
+ // Handle incoming challenge when app opens from share
551
+ const launchParams = VenusAPI.getLaunchParams()
552
+ if (launchParams.challengeType === 'highscore') {
553
+ const targetScore = parseInt(launchParams.scoreTobeat, 10)
554
+ const challengerId = launchParams.challengerId
555
+ startHighScoreChallenge(targetScore, challengerId)
556
+ }
557
+
558
+ // Handle daily puzzle invites
559
+ if (launchParams.challengeType === 'daily') {
560
+ const puzzleId = launchParams.dailyPuzzleId
561
+ const inviter = launchParams.invitedBy
562
+ loadDailyPuzzle(puzzleId, inviter)
563
+ }
564
+
565
+ // Referral system example
566
+ if (launchParams.referredBy) {
567
+ await rewardReferrer(launchParams.referredBy)
568
+ showMessage(`You were invited by ${launchParams.referredBy}!`)
569
+ }
570
+ ```
571
+
572
+ **Launch Parameters:**
573
+
574
+ Launch parameters are completely arbitrary - define whatever your game needs:
575
+
576
+ Examples from the code above:
577
+ - `challengeType`, `scoreTobeat`, `challengerId` - For beat-my-score challenges
578
+ - `dailyPuzzleId`, `invitedBy` - For daily puzzle invites
579
+ - `referredBy` - For referral tracking
580
+ - `levelId`, `replayId`, `customMapId` - For UGC content
581
+
582
+ All parameters are custom game data - no reserved or required fields.
583
+
584
+ **Size Limits:**
585
+
586
+ - **Max total size**: Keep `launchParams` under ~100KB (share data stored in Firestore with 1MB document limit)
587
+ - **Use compact formats**: IDs and short strings work best
588
+ - **Best practice**: Store large UGC separately and only pass an ID in `launchParams`
589
+
590
+ ---
591
+
592
+ ### Analytics API
593
+
594
+ ```typescript
595
+ // Log custom event
596
+ await VenusAPI.analytics.logEvent('level_complete', {
597
+ level: 5,
598
+ score: 1000,
599
+ timeElapsed: 120
600
+ })
601
+
602
+ // Set user properties
603
+ await VenusAPI.analytics.setUserProperty('vip_status', 'gold')
604
+ ```
605
+
606
+ ---
607
+
608
+ ### Avatar 3D API
609
+
610
+ ```typescript
611
+ // Load current avatar configuration
612
+ const avatar = await VenusAPI.avatar3d.loadAvatar()
613
+ // Or load a specific avatar
614
+ const avatarConfig = await VenusAPI.avatar3d.loadAvatar('avatar_123')
615
+
616
+ // Show avatar editor
617
+ const result = await VenusAPI.avatar3d.showEditor({
618
+ currentAvatar: avatarConfig,
619
+ contextData: { source: 'settings' }
620
+ })
621
+
622
+ if (result.wasChanged && result.savedAvatarId) {
623
+ console.log('Avatar updated:', result.savedAvatarId)
624
+ }
625
+
626
+ // Save avatar
627
+ const avatarId = await VenusAPI.avatar3d.saveAvatar(avatarConfig)
628
+
629
+ // Delete avatar
630
+ await VenusAPI.avatar3d.deleteAvatar()
631
+
632
+ // Download avatar manifest
633
+ const manifest = await VenusAPI.avatar3d.downloadManifest()
634
+
635
+ // Download asset paths
636
+ const assetPaths = await VenusAPI.avatar3d.downloadAssetPaths()
637
+ ```
638
+
639
+ ---
640
+
641
+ ### Rooms API
642
+
643
+ Multi-user room management:
644
+
645
+ ```typescript
646
+ // Get current room
647
+ const room = await VenusAPI.rooms.getCurrentRoom()
648
+ // Returns: { id, name, participants, metadata }
649
+
650
+ // Join room
651
+ await VenusAPI.rooms.join('room_123')
652
+
653
+ // Leave room
654
+ await VenusAPI.rooms.leave()
655
+
656
+ // Send room message
657
+ await VenusAPI.rooms.sendMessage({
658
+ type: 'game_action',
659
+ data: { action: 'move', x: 10, y: 20 }
660
+ })
661
+ ```
662
+
663
+ ---
664
+
665
+ ### Time API
666
+
667
+ Server time synchronization and formatting with automatic locale detection:
668
+
669
+ ```typescript
670
+ // Get server time
671
+ const serverTimeData = await VenusAPI.time.requestTimeAsync()
672
+ // Returns: { serverTime, localTime, timezoneOffset, formattedTime, locale }
673
+
674
+ // Format time (locale is automatically determined from user settings)
675
+ const formatted = VenusAPI.time.formatTime(Date.now(), {
676
+ dateStyle: 'full', // 'full', 'long', 'medium', 'short'
677
+ timeStyle: 'medium',
678
+ hour12: true
679
+ })
680
+
681
+ // Format number (locale is automatically determined from user settings)
682
+ const formattedNumber = VenusAPI.time.formatNumber(1234567.89, {
683
+ style: 'currency',
684
+ currency: 'USD',
685
+ minimumFractionDigits: 2,
686
+ maximumFractionDigits: 2
687
+ })
688
+
689
+ // Get future time
690
+ const futureTime = await VenusAPI.time.getFutureTimeAsync({
691
+ days: 1,
692
+ hours: 2,
693
+ minutes: 30
694
+ })
695
+ ```
696
+
697
+ ---
698
+
699
+ ### CDN API
700
+
701
+ ```typescript
702
+ // Resolve asset URLs (synchronous)
703
+ const assetUrl = VenusAPI.cdn.resolveAssetUrl('images/logo.png')
704
+ const avatarUrl = VenusAPI.cdn.resolveAvatarAssetUrl('avatars/model.glb')
705
+ const libUrl = VenusAPI.cdn.resolveSharedLibUrl('libs/helper.js')
706
+
707
+ // Get CDN base URL
708
+ const baseUrl = VenusAPI.cdn.getAssetCdnBaseUrl()
709
+
710
+ // Fetch from CDN
711
+ const response = await VenusAPI.cdn.fetchFromCdn('https://cdn.example.com/file.json')
712
+ const blob = await VenusAPI.cdn.fetchBlob('path/to/asset.png')
713
+ ```
714
+
715
+ ---
716
+
717
+ ### Features API
718
+
719
+ Feature flags, experiments, and A/B testing:
720
+
721
+ ```typescript
722
+ // Get feature flag value (returns boolean)
723
+ const enabled = await VenusAPI.features.getFeatureFlag('new_ui_enabled')
724
+
725
+ // Get feature gate (returns boolean)
726
+ const canAccess = await VenusAPI.features.getFeatureGate('beta_features')
727
+
728
+ // Get experiment variant
729
+ const experiment = await VenusAPI.features.getExperiment('checkout_flow')
730
+ // Returns: { name, ruleID, value, groupName } | null
731
+ ```
732
+
733
+ ### Lifecycle API
734
+
735
+ App lifecycle event handlers:
736
+
737
+ ```typescript
738
+ // Register lifecycle callbacks
739
+ VenusAPI.lifecycle.onReady(() => {
740
+ console.log('App ready')
741
+ })
742
+
743
+ VenusAPI.lifecycle.onShow((context) => {
744
+ console.log('App shown', context.hudInsets)
745
+ })
746
+
747
+ VenusAPI.lifecycle.onPlay((context) => {
748
+ console.log('App playing', context.hudInsets)
749
+ })
750
+
751
+ VenusAPI.lifecycle.onPause(() => {
752
+ console.log('App paused')
753
+ })
754
+
755
+ VenusAPI.lifecycle.onResume(() => {
756
+ console.log('App resumed')
757
+ })
758
+
759
+ VenusAPI.lifecycle.onHidden(() => {
760
+ console.log('App hidden')
761
+ })
762
+
763
+ VenusAPI.lifecycle.onQuit(() => {
764
+ console.log('App quitting')
765
+ })
766
+
767
+ // Quit the app
768
+ await VenusAPI.lifecycle.quit()
769
+ ```
770
+
771
+ ---
772
+
773
+ ### Logging API
774
+
775
+ ```typescript
776
+ // Log messages
777
+ VenusAPI.logging.log('Info message', { data: 'value' })
778
+ VenusAPI.logging.error('Error message', error)
779
+ VenusAPI.logging.debug('Debug info')
780
+ ```
781
+
782
+ ---
783
+
784
+ ### Leaderboard API (BETA)
785
+
786
+ Competitive leaderboards with three security levels. Choose based on your game's requirements.
787
+
788
+ ---
789
+
790
+ #### 🟢 Simple Mode (Default - Casual Games)
791
+
792
+ Submit scores directly without tokens:
793
+
794
+ ```typescript
795
+ // One call - no token needed!
796
+ const result = await VenusAPI.leaderboard.submitScoreAsync({
797
+ score: 1500,
798
+ duration: 120,
799
+ mode: 'classic',
800
+ metadata: {
801
+ levelCompleted: 10,
802
+ powerUpsUsed: 3
803
+ },
804
+ telemetry: {
805
+ clickCount: 245,
806
+ avgReactionTime: 0.32
807
+ }
808
+ })
809
+
810
+ console.log(`Your rank: ${result.rank}`)
811
+ ```
812
+
813
+ **Configuration:** None needed (uses defaults)
814
+
815
+ **Security provided:**
816
+ - ✅ Score/duration bounds validation
817
+ - ✅ Rate limiting (60 second cooldown per player)
818
+ - ✅ Trust scores & shadow banning for repeat offenders
819
+ - ❌ No session replay protection
820
+ - ❌ No tamper protection
821
+
822
+ **Best for:** Simple integration
823
+
824
+ ---
825
+
826
+ #### 🟡 Token Mode (Competitive Games)
827
+
828
+ Add session validation for replay protection:
829
+
830
+ ```typescript
831
+ // Step 1: Create score token
832
+ const scoreToken = await VenusAPI.leaderboard.createScoreTokenAsync({
833
+ mode: 'ranked'
834
+ })
835
+ // Returns: { token, startTime, expiresAt, mode }
836
+
837
+ // Step 2: Play game...
838
+
839
+ // Step 3: Submit with token
840
+ const result = await VenusAPI.leaderboard.submitScoreAsync({
841
+ token: scoreToken.token,
842
+ score: 1500,
843
+ duration: 120,
844
+ metadata: { ... }
845
+ })
846
+ ```
847
+
848
+ **Configuration:**
849
+ ```json
850
+ {
851
+ "leaderboard": {
852
+ "requiresToken": true
853
+ }
854
+ }
855
+ ```
856
+
857
+ **Additional security:**
858
+ - ✅ All simple mode security
859
+ - ✅ Session validation (tokens expire in 1 hour)
860
+ - ✅ Replay attack prevention (one-time use)
861
+ - ✅ Mode locking (token locks game mode)
862
+ - ❌ No tamper protection
863
+
864
+ **Best for:** Preventing replay attacks
865
+
866
+ ---
867
+
868
+ #### 🔴 Score Sealing Mode (High-Stakes Games)
869
+
870
+ Add cryptographic tamper protection:
871
+
872
+ ```typescript
873
+ // Step 1: Create score token (sealing data included automatically if enabled)
874
+ const scoreToken = await VenusAPI.leaderboard.createScoreTokenAsync({
875
+ mode: 'tournament'
876
+ })
877
+ // Returns: { token, sealingNonce, sealingSecret, ... }
878
+
879
+ // Step 2: Play game...
880
+
881
+ // Step 3: Submit score - SDK auto-computes hash internally!
882
+ const result = await VenusAPI.leaderboard.submitScoreAsync({
883
+ token: scoreToken.token,
884
+ score: 1500,
885
+ duration: 120,
886
+ })
887
+ ```
888
+
889
+ **Configuration:**
890
+ ```json
891
+ {
892
+ "leaderboard": {
893
+ "requiresToken": true,
894
+ "enableScoreSealing": true,
895
+ "scoreSealingSecret": "your-secret-key-change-in-production"
896
+ }
897
+ }
898
+ ```
899
+
900
+ **Note:** Hash computation is handled internally by the SDK using Web Crypto API (HMAC-SHA256). Games never need to implement cryptographic hashing manually. The hash always includes: `score`, `duration`, and `token`.
901
+
902
+ **Maximum security:**
903
+ - ✅ All token mode security
904
+ - ✅ Tamper-proof scores (HMAC-SHA256 verification)
905
+ - ✅ Client-side cheat detection
906
+ - ✅ Automatic hash computation (no crypto code needed in games)
907
+
908
+ **Best for:** Reduced hacking
909
+
910
+ ---
911
+
912
+ #### Query Methods (Same for All Modes)
913
+
914
+ All query methods work identically regardless of security mode:
915
+
916
+ ```typescript
917
+ // Get paginated scores
918
+ const pagedScores = await VenusAPI.leaderboard.getPagedScoresAsync({
919
+ mode: 'classic',
920
+ period: 'daily',
921
+ limit: 50,
922
+ cursor: nextCursor
923
+ })
924
+
925
+ // Get podium + player context
926
+ const podiumScores = await VenusAPI.leaderboard.getPodiumScoresAsync({
927
+ mode: 'classic',
928
+ period: 'daily',
929
+ topCount: 3,
930
+ contextAhead: 4,
931
+ contextBehind: 2
932
+ })
933
+
934
+ // Get my rank
935
+ const rank = await VenusAPI.leaderboard.getMyRankAsync({
936
+ mode: 'classic',
937
+ period: 'daily'
938
+ })
939
+ ```
940
+
941
+ ---
942
+
943
+ #### Configuration Reference
944
+
945
+ Add a `leaderboard` object to your game's `config.json` file:
946
+
947
+ ```json
948
+ {
949
+ "leaderboard": {
950
+ // Basic settings
951
+ "minScore": 0,
952
+ "maxScore": 999999999,
953
+ "minDurationSec": 10,
954
+ "maxDurationSec": 600,
955
+
956
+ // Security (progressive levels)
957
+ "requiresToken": false, // Simple mode (default)
958
+ "enableScoreSealing": false, // Requires requiresToken=true
959
+ "scoreSealingSecret": "secret", // Required if enableScoreSealing=true
960
+
961
+ // Game modes
962
+ "modes": {
963
+ "default": { "displayName": "Normal" },
964
+ "hard": { "displayName": "Hard Mode" }
965
+ },
966
+
967
+ // Time periods
968
+ "periods": {
969
+ "daily": { "displayName": "Daily", "type": "daily" },
970
+ "alltime": { "displayName": "All Time", "type": "alltime" }
971
+ },
972
+
973
+ // Anti-cheat
974
+ "antiCheat": {
975
+ "enableRateLimit": true,
976
+ "minTimeBetweenSubmissionsSec": 60,
977
+ "trustScoreDecayPerFlag": 10,
978
+ "shadowBanThreshold": 20,
979
+ "enableZScoreDetection": false,
980
+ "zScoreThreshold": 3
981
+ },
982
+
983
+ // Display
984
+ "displaySettings": {
985
+ "maxEntriesPerPage": 50
986
+ },
987
+
988
+ // Seed data (optional)
989
+ "seedEntries": {
990
+ "default": {
991
+ "daily": [
992
+ {
993
+ "score": 18500,
994
+ "username": "ProPlayer",
995
+ "duration": 180
996
+ },
997
+ {
998
+ "score": 15200,
999
+ "username": "Challenger",
1000
+ "duration": 210
1001
+ }
1002
+ ]
1003
+ }
1004
+ }
1005
+ }
1006
+ }
1007
+ ```
1008
+
1009
+
1010
+
1011
+
1012
+ **Features:**
1013
+ - **Three Security Levels**: Simple, Token, Sealed - choose based on game stakes
1014
+ - **Multiple Modes**: Support different game modes (classic, hard, etc.)
1015
+ - **Time Periods**: Daily, weekly, monthly, and all-time leaderboards
1016
+ - **Anti-Cheat**: Rate limiting, trust scores, shadow banning, optional session validation & sealing
1017
+ - **Seed Entries**: Pre-populate leaderboards with NPC scores
1018
+ - **Pagination**: Cursor-based pagination for large leaderboards
1019
+ - **UTC-Based Periods**: All players globally compete in same daily/weekly/monthly periods
1020
+
1021
+
1022
+ ---
1023
+
1024
+ ## Mock Mode
1025
+
1026
+ All APIs have complete mock implementations for local development:
1027
+
1028
+ ```typescript
1029
+ import { default as VenusAPI } from '@series-inc/venus-sdk/api'
1030
+
1031
+ await VenusAPI.initializeAsync({ mock: true })
1032
+
1033
+ // All APIs work the same, but with simulated responses
1034
+ const state = await VenusAPI.simulation.getStateAsync()
1035
+ ```
1036
+
1037
+ ### Custom Mock Data
1038
+
1039
+ ```typescript
1040
+ await VenusAPI.initializeAsync({
1041
+ mock: {
1042
+ simulation: {
1043
+ state: { customData: 'value' }
1044
+ },
1045
+ profile: {
1046
+ name: 'Test User',
1047
+ username: 'test_user'
1048
+ }
1049
+ }
1050
+ })
1051
+ ```
1052
+
1053
+ ---
1054
+
1055
+ ## RPC Transport
1056
+
1057
+ The SDK uses an RPC (Remote Procedure Call) architecture for communication:
1058
+
1059
+ ```typescript
1060
+ import { RpcClient, VenusTransport } from 'venus-sdk'
1061
+
1062
+ // Low-level RPC client
1063
+ const transport = new VenusTransport()
1064
+ const rpcClient = new RpcClient(transport)
1065
+
1066
+ // Send request
1067
+ const response = await rpcClient.request({
1068
+ method: 'simulation.getState',
1069
+ params: { roomId: 'room_123' }
1070
+ })
1071
+ ```
1072
+
1073
+ ---
1074
+
1075
+ ## Build Configuration
1076
+
1077
+ The package is built with `tsup` and provides multiple module formats:
1078
+
1079
+ ```json
1080
+ {
1081
+ "main": "./dist/index.cjs",
1082
+ "module": "./dist/index.mjs",
1083
+ "types": "./dist/index.d.ts",
1084
+ "exports": {
1085
+ ".": {
1086
+ "types": "./dist/index.d.ts",
1087
+ "import": "./dist/index.mjs",
1088
+ "require": "./dist/index.cjs"
1089
+ },
1090
+ "./api": {
1091
+ "types": "./dist/venus-api/index.d.ts",
1092
+ "import": "./dist/venus-api/index.mjs",
1093
+ "require": "./dist/venus-api/index.cjs"
1094
+ }
1095
+ }
1096
+ }
1097
+ ```
1098
+
1099
+ ---
1100
+
1101
+ ## TypeScript Configuration
1102
+
1103
+ The package uses TypeScript 5.9+ with strict type checking:
1104
+
1105
+ ```json
1106
+ {
1107
+ "compilerOptions": {
1108
+ "strict": true,
1109
+ "target": "ES2020",
1110
+ "module": "ESNext",
1111
+ "moduleResolution": "bundler"
1112
+ }
1113
+ }
1114
+ ```
1115
+
1116
+ ---
1117
+
1118
+ ## Testing
1119
+
1120
+ ```bash
1121
+ # Run unit tests
1122
+ npm test
1123
+
1124
+ # Run tests in watch mode
1125
+ npm test -- --watch
1126
+ ```
1127
+
1128
+ Tests are written using Jest with JSDOM environment for browser API simulation.
1129
+
1130
+ ---
1131
+
1132
+ ## Embedded Libraries (Vite)
1133
+
1134
+ For **Vite projects**, use the included plugin to automatically reduce bundle size by using embedded libraries:
1135
+
1136
+ ```bash
1137
+ npm install @series-inc/venus-sdk
1138
+ ```
1139
+
1140
+ ```typescript
1141
+ // vite.config.ts
1142
+ import { venusLibrariesPlugin } from '@series-inc/venus-sdk/vite';
1143
+
1144
+ export default defineConfig({
1145
+ plugins: [venusLibrariesPlugin({ appName: 'my-game' })],
1146
+ build: { target: 'es2022' } // Required for top-level await
1147
+ });
1148
+ ```
1149
+
1150
+ **Build commands:**
1151
+ - `npm run build` → Embedded libraries (default, optimal)
1152
+ - `VENUS_DISABLE_EMBEDDED_LIBS=true npm run build` → Bundled (standalone)
1153
+
1154
+ **Supported libraries:** Phaser, React, ReactDOM, Three.js, Matter.js, inkjs, Zustand
1155
+
1156
+ See `src/vite/README.md` for details.
1157
+
1158
+ ### For Non-Vite Bundlers
1159
+
1160
+ The Vite plugin does three things you can recreate in any bundler:
1161
+
1162
+ **1. Externalize library imports** - Replace imports with virtual modules:
1163
+ ```javascript
1164
+ // Input: import Phaser from 'phaser';
1165
+ // Output: const lib = await (async () => {
1166
+ // await window.__venusLibraryShim.ready();
1167
+ // return window.__venusLibraryExports['phaser@3.90.0'];
1168
+ // })();
1169
+ // export default lib;
1170
+ ```
1171
+
1172
+ **2. Inject config into HTML `<head>`:**
1173
+ ```html
1174
+ <script>
1175
+ window.__venusLibrariesConfig = {
1176
+ enabled: true,
1177
+ required: ["phaser@3.90.0"],
1178
+ manifest: { "phaser@3.90.0": { cdnPath: "...", globalVar: "Phaser" } },
1179
+ cdnBase: "https://venus-static-01293ak.web.app/libs/"
1180
+ };
1181
+ </script>
1182
+ ```
1183
+
1184
+ **3. Inject minimal shim** (loads from CDN, resolves `ready()` promise):
1185
+ ```javascript
1186
+ window.__venusLibraryShim = { ready: () => Promise };
1187
+ // Fetch libraries from CDN, evaluate, register in __venusLibraryExports
1188
+ ```
1189
+
1190
+ See `embeddedLibrariesManifest.ts` for library definitions and `webviewLibraryShimSource.ts` for the full shim (used on mobile).
1191
+
1192
+ ---
28
1193
 
29
- The complete Venus SDK manuals live on [Venus Docs](https://series-1.gitbook.io/getreel-docs). Start there for setup guides, API references, tutorials, and best practices.
1194
+ ## Related
30
1195
 
31
- ## Support & Links
1196
+ - [Main Repository](https://github.com/SeriesAI/venus-sdk)
1197
+ - [npm Package](https://www.npmjs.com/package/venus-sdk)
1198
+ - [Issue Tracker](https://github.com/SeriesAI/venus-sdk/issues)
32
1199
 
33
- - [Join our Discord!](https://discord.gg/NcjhKQHx)