@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 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
+