@series-inc/venus-sdk 3.0.2 → 3.0.4

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 CHANGED
@@ -690,6 +690,192 @@ VenusAPI.logging.debug('Debug info')
690
690
 
691
691
  ---
692
692
 
693
+ ### Leaderboard API (BETA)
694
+
695
+ Competitive leaderboards with anti-cheat, multiple modes, and time periods.
696
+
697
+ #### API Methods
698
+
699
+ ```typescript
700
+ // Start a leaderboard session
701
+ const session = await VenusAPI.leaderboard.startRunAsync({
702
+ mode: 'classic' // Optional: 'classic', 'hard', etc. Defaults to 'default'
703
+ })
704
+ // Returns: { sessionId, startTime, expiresAt, hashNonce?, mode }
705
+
706
+ // Submit a score (within 1 hour of starting session)
707
+ const result = await VenusAPI.leaderboard.submitScoreAsync({
708
+ sessionId: session.sessionId,
709
+ score: 1500,
710
+ durationSec: 120,
711
+ mode: 'classic', // Optional: must match session mode
712
+ metadata: { // Optional: game-specific data (max 20KB)
713
+ levelCompleted: 10,
714
+ powerUpsUsed: 3
715
+ },
716
+ telemetry: { // Optional: anti-cheat data (max 2KB, primitives only)
717
+ clickCount: 245,
718
+ avgReactionTime: 0.32
719
+ },
720
+ hash: computedHash // Required if leaderboard uses hash verification
721
+ })
722
+ // Returns: { accepted, rank, zScore, isAnomaly }
723
+
724
+ // Get leaderboard (paginated)
725
+ const leaderboard = await VenusAPI.leaderboard.getLeaderboardAsync({
726
+ mode: 'classic', // Optional: game mode
727
+ period: 'daily', // Optional: 'daily', 'weekly', 'monthly', 'alltime'
728
+ periodDate: Date.now(), // Optional: specific period to view
729
+ limit: 50, // Optional: entries per page (max 50)
730
+ cursor: nextCursor // Optional: for pagination
731
+ })
732
+ // Returns: {
733
+ // variant: 'standard',
734
+ // entries: [{ profileId, username, avatarUrl, score, rank, ... }],
735
+ // totalEntries: 1234,
736
+ // nextCursor: 'abc123...',
737
+ // playerRank: 42,
738
+ // periodInstance: 'daily_2025-11-04'
739
+ // }
740
+
741
+ // Get leaderboard highlight (top players + context around you)
742
+ const highlight = await VenusAPI.leaderboard.getLeaderboardHighlightAsync({
743
+ mode: 'classic',
744
+ period: 'daily',
745
+ topCount: 3, // Top N players (podium)
746
+ contextAhead: 4, // Players ahead of you
747
+ contextBehind: 2 // Players behind you
748
+ })
749
+ // Returns: {
750
+ // variant: 'highlight',
751
+ // entries: [...],
752
+ // context: {
753
+ // topEntries: [...], // Top 3
754
+ // beforePlayer: [...], // 4 players ahead
755
+ // playerEntry: {...}, // Your entry
756
+ // afterPlayer: [...], // 2 players behind
757
+ // omittedBefore: 35, // Gap between top 3 and you
758
+ // omittedAfter: 100 // Players below you
759
+ // },
760
+ // playerRank: 42,
761
+ // totalEntries: 150
762
+ // }
763
+
764
+ // Get player stats
765
+ const stats = await VenusAPI.leaderboard.getPlayerStatsAsync({
766
+ mode: 'classic',
767
+ period: 'daily'
768
+ })
769
+ // Returns: {
770
+ // rank: 42,
771
+ // score: 1500,
772
+ // totalPlayers: 150,
773
+ // percentile: 0.72, // 72nd percentile
774
+ // trustScore: 85,
775
+ // periodInstance: 'daily_2025-11-04'
776
+ // }
777
+ ```
778
+
779
+ #### Configuration
780
+
781
+ Add a `leaderboard` object to your game's `config.json` file:
782
+
783
+ ```json
784
+ {
785
+ "leaderboard": {
786
+ "isDisabled": false,
787
+ "disabledMessage": "Leaderboards are temporarily unavailable.",
788
+ "requiresHash": true,
789
+ "hashSecret": "your-secret-key-change-in-production",
790
+ "scoringFields": ["score", "durationSec", "sessionId"],
791
+ "minDurationSec": 10,
792
+ "maxDurationSec": 600,
793
+ "minScore": 0,
794
+ "maxScore": 999999999,
795
+ "modes": {
796
+ "default": {
797
+ "displayName": "Classic Mode"
798
+ },
799
+ "hard": {
800
+ "displayName": "Hard Mode",
801
+ "minDurationSec": 5,
802
+ "maxDurationSec": 300
803
+ }
804
+ },
805
+ "periods": {
806
+ "daily": {
807
+ "displayName": "Daily",
808
+ "type": "daily"
809
+ },
810
+ "alltime": {
811
+ "displayName": "All Time",
812
+ "type": "alltime"
813
+ }
814
+ },
815
+ "antiCheat": {
816
+ "enableZScoreDetection": false,
817
+ "zScoreThreshold": 3,
818
+ "enableRateLimit": true,
819
+ "minTimeBetweenSubmissionsSec": 60,
820
+ "trustScoreDecayPerFlag": 10,
821
+ "shadowBanThreshold": 20
822
+ },
823
+ "displaySettings": {
824
+ "maxEntriesPerPage": 50
825
+ },
826
+ "seedEntries": {
827
+ "default": {
828
+ "daily": [
829
+ {
830
+ "score": 18500,
831
+ "username": "ProPlayer",
832
+ "avatarUrl": null,
833
+ "durationSec": 180
834
+ },
835
+ {
836
+ "score": 15200,
837
+ "username": "Challenger",
838
+ "avatarUrl": null,
839
+ "durationSec": 210
840
+ }
841
+ ]
842
+ }
843
+ }
844
+ }
845
+ }
846
+ ```
847
+
848
+ **Configuration Options:**
849
+
850
+ - `isDisabled`: Globally disable leaderboards
851
+ - `requiresHash`: Enable HMAC-based score verification (recommended for production)
852
+ - `hashSecret`: Secret key for HMAC verification (keep this secure!)
853
+ - `scoringFields`: Fields included in hash verification (can include nested fields like `metadata.level`)
854
+ - `minDurationSec` / `maxDurationSec`: Valid gameplay duration range
855
+ - `minScore` / `maxScore`: Valid score bounds
856
+ - `modes`: Game modes (can override min/max values per mode)
857
+ - `periods`: Time periods for leaderboards (`daily`, `weekly`, `monthly`, `alltime`)
858
+ - `antiCheat`: Anti-cheat settings
859
+ - `seedEntries`: Pre-populate leaderboards with NPC scores (nested by mode → period)
860
+
861
+ **Features:**
862
+ - **Multiple Modes**: Support different game modes (classic, hard, etc.)
863
+ - **Time Periods**: Daily, weekly, monthly, and all-time leaderboards
864
+ - **Anti-Cheat**: Session validation, rate limiting, hash verification, z-score anomaly detection
865
+ - **Shadow Banning**: Cheaters see their own scores but are hidden from others
866
+ - **Trust Scores**: Per-player reputation that decays with suspicious behavior
867
+ - **Seed Entries**: Pre-populate leaderboards with NPC scores
868
+ - **Pagination**: Cursor-based pagination for large leaderboards
869
+ - **UTC-Based Periods**: All players globally compete in same daily/weekly/monthly periods
870
+
871
+ **Security Notes:**
872
+ - Session tokens expire after 1 hour and can only be used once to prevent replay attacks
873
+ - Use `requiresHash: true` in production with a strong `hashSecret`
874
+ - Keep `hashSecret` out of version control (use environment variables or local config)
875
+ - Store `hashSecret` in `config.local.json` (gitignored) for local development
876
+
877
+ ---
878
+
693
879
  ## Mock Mode
694
880
 
695
881
  All APIs have complete mock implementations for local development:
@@ -1160,7 +1160,8 @@ var MockCdnApi = class {
1160
1160
  return index === pathParts.length - 1 ? encodeURIComponent(part) : part;
1161
1161
  });
1162
1162
  const encodedSubPath = encodedParts.join("/");
1163
- const fullUrl = `${this.baseUrl}${encodedSubPath}`;
1163
+ const cacheBust = Date.now();
1164
+ const fullUrl = `${this.baseUrl}${encodedSubPath}?cacheBust=${cacheBust}`;
1164
1165
  return fullUrl;
1165
1166
  }
1166
1167
  resolveAvatarAssetUrl(subPath) {
@@ -1553,10 +1554,10 @@ function initializeLifecycleApi(venusApi, host) {
1553
1554
  // src/logging/MockLoggingApi.ts
1554
1555
  var MockLoggingApi = class {
1555
1556
  logDebug(message, ...args) {
1556
- console.log(`[Venus Mock] ${message}`, args);
1557
+ console.log(`[Venus Mock] ${message}`, ...args);
1557
1558
  }
1558
1559
  logError(message, ...args) {
1559
- console.error(`[Venus Mock] ${message}`, args);
1560
+ console.error(`[Venus Mock] ${message}`, ...args);
1560
1561
  }
1561
1562
  };
1562
1563
 
@@ -3544,7 +3545,7 @@ function initializeTime(venusApi, host) {
3544
3545
  }
3545
3546
 
3546
3547
  // src/version.ts
3547
- var SDK_VERSION = "3.0.2";
3548
+ var SDK_VERSION = "3.0.4";
3548
3549
 
3549
3550
  // src/shared-assets/consts.ts
3550
3551
  var BurgerTimeAssetsCdnPath = "burger-time/Core.stow";
@@ -4954,6 +4955,7 @@ var MockHost = class {
4954
4955
  tryResume() {
4955
4956
  if (this.state === 1 /* PAUSED */) {
4956
4957
  this.triggerLifecycleEvent("RESUME" /* RESUME */);
4958
+ this.state = 0 /* PLAYING */;
4957
4959
  }
4958
4960
  }
4959
4961
  async showAdOverlay(type) {
@@ -5288,5 +5290,5 @@ function initializeSocial(venusApi, host) {
5288
5290
  }
5289
5291
 
5290
5292
  export { HapticFeedbackStyle, HostCdnApi, HostProfileApi, HostTimeApi, MockAdsApi, MockAiApi, MockAnalyticsApi, MockAvatarApi, MockCdnApi, MockFeaturesApi, MockHapticsApi, MockIapApi, MockLeaderboardApi, MockLifecycleApi, MockLoggingApi, MockNavigationApi, MockNotificationsApi, MockPopupsApi, MockPreloaderApi, MockProfileApi, MockSharedAssetsApi, MockSimulationApi, MockSocialApi, MockStorageApi, MockTimeApi, RemoteHost, RpcAdsApi, RpcAiApi, RpcAnalyticsApi, RpcAvatarApi, RpcClient, RpcFeaturesApi, RpcHapticsApi, RpcIapApi, RpcLeaderboardApi, RpcLifecycleApi, RpcLoggingApi, RpcNavigationApi, RpcNotificationsApi, RpcPopupsApi, RpcPreloaderApi, RpcSharedAssetsApi, RpcSimulationApi, RpcSocialApi, RpcStorageApi, SDK_VERSION, VenusMessageId, VenusRoom, createHost, createMockStorageApi, init_rooms, initializeAds, initializeAi, initializeAnalytics, initializeAvatar3d, initializeCdn, initializeFeaturesApi, initializeHaptics, initializeIap, initializeLeaderboard, initializeLifecycleApi, initializeLocalNotifications, initializeLoggingApi, initializePopups, initializePost, initializePreloader, initializeProfile, initializeRoomsApi, initializeSimulation, initializeSocial, initializeStackNavigation, initializeStorage, initializeTime, isPacificDaylightTime, setupRoomNotifications };
5291
- //# sourceMappingURL=chunk-NQGU2VZM.mjs.map
5292
- //# sourceMappingURL=chunk-NQGU2VZM.mjs.map
5293
+ //# sourceMappingURL=chunk-PXWCNWJ6.mjs.map
5294
+ //# sourceMappingURL=chunk-PXWCNWJ6.mjs.map