@series-inc/venus-sdk 3.1.2 → 3.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.
Files changed (38) hide show
  1. package/dist/{AdsApi-CNGRf6j0.d.mts → AdsApi-DFutZ7_q.d.mts} +501 -293
  2. package/dist/{AdsApi-CNGRf6j0.d.ts → AdsApi-DFutZ7_q.d.ts} +501 -293
  3. package/dist/{chunk-PXWCNWJ6.mjs → chunk-AGXMORDL.mjs} +1442 -1586
  4. package/dist/chunk-AGXMORDL.mjs.map +1 -0
  5. package/dist/chunk-NSSMTXJJ.mjs +7 -0
  6. package/dist/chunk-NSSMTXJJ.mjs.map +1 -0
  7. package/dist/{chunk-W7IPHM67.mjs → chunk-QABXMFND.mjs} +3 -26
  8. package/dist/chunk-QABXMFND.mjs.map +1 -0
  9. package/dist/chunk-UXY5CKKG.mjs +12 -0
  10. package/dist/chunk-UXY5CKKG.mjs.map +1 -0
  11. package/dist/core-62LWDHN7.mjs +4 -0
  12. package/dist/{core-R3FHW62G.mjs.map → core-62LWDHN7.mjs.map} +1 -1
  13. package/dist/index.cjs +1461 -1585
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.mts +280 -92
  16. package/dist/index.d.ts +280 -92
  17. package/dist/index.mjs +4 -6
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/venus-api/index.cjs +1557 -2020
  20. package/dist/venus-api/index.cjs.map +1 -1
  21. package/dist/venus-api/index.d.mts +2 -2
  22. package/dist/venus-api/index.d.ts +2 -2
  23. package/dist/venus-api/index.mjs +92 -391
  24. package/dist/venus-api/index.mjs.map +1 -1
  25. package/dist/vite/index.cjs +534 -0
  26. package/dist/vite/index.cjs.map +1 -0
  27. package/dist/vite/index.mjs +527 -0
  28. package/dist/vite/index.mjs.map +1 -0
  29. package/dist/webview/index.cjs +15 -0
  30. package/dist/webview/index.cjs.map +1 -0
  31. package/dist/webview/index.d.mts +15 -0
  32. package/dist/webview/index.d.ts +15 -0
  33. package/dist/webview/index.mjs +4 -0
  34. package/dist/webview/index.mjs.map +1 -0
  35. package/package.json +1 -1
  36. package/dist/chunk-PXWCNWJ6.mjs.map +0 -1
  37. package/dist/chunk-W7IPHM67.mjs.map +0 -1
  38. package/dist/core-R3FHW62G.mjs +0 -3
@@ -1,9 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
5
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
6
  var __esm = (fn, res) => function __init() {
9
7
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -12,15 +10,6 @@ var __export = (target, all) => {
12
10
  for (var name in all)
13
11
  __defProp(target, name, { get: all[name], enumerable: true });
14
12
  };
15
- var __copyProps = (to, from, except, desc) => {
16
- if (from && typeof from === "object" || typeof from === "function") {
17
- for (let key of __getOwnPropNames(from))
18
- if (!__hasOwnProp.call(to, key) && key !== except)
19
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
- }
21
- return to;
22
- };
23
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
13
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
25
14
 
26
15
  // src/venus-api/systems/core.js
@@ -111,221 +100,6 @@ var init_core = __esm({
111
100
  }
112
101
  });
113
102
 
114
- // src/rooms/RoomsApi.ts
115
- var init_RoomsApi = __esm({
116
- "src/rooms/RoomsApi.ts"() {
117
- }
118
- });
119
-
120
- // src/rooms/VenusRoom.ts
121
- var VenusRoom;
122
- var init_VenusRoom = __esm({
123
- "src/rooms/VenusRoom.ts"() {
124
- VenusRoom = class {
125
- constructor(roomData) {
126
- __publicField(this, "id");
127
- __publicField(this, "name");
128
- __publicField(this, "players");
129
- __publicField(this, "maxPlayers");
130
- __publicField(this, "gameType");
131
- __publicField(this, "appId");
132
- __publicField(this, "type");
133
- __publicField(this, "createdBy");
134
- __publicField(this, "createdAt");
135
- __publicField(this, "updatedAt");
136
- __publicField(this, "isPrivate");
137
- __publicField(this, "currentPlayers");
138
- __publicField(this, "status");
139
- __publicField(this, "customMetadata");
140
- __publicField(this, "admins");
141
- __publicField(this, "roomCode");
142
- __publicField(this, "description");
143
- __publicField(this, "data");
144
- __publicField(this, "version");
145
- __publicField(this, "_subscriptions", /* @__PURE__ */ new Map());
146
- this.id = roomData.id;
147
- this.name = roomData.name;
148
- this.players = roomData.currentPlayers || [];
149
- this.maxPlayers = roomData.maxPlayers;
150
- this.gameType = roomData.gameType;
151
- this.appId = roomData.appId;
152
- this.type = roomData.type;
153
- this.createdBy = roomData.createdBy;
154
- this.createdAt = roomData.createdAt;
155
- this.updatedAt = roomData.updatedAt;
156
- this.isPrivate = roomData.isPrivate;
157
- this.currentPlayers = roomData.currentPlayers || [];
158
- this.status = roomData.status;
159
- this.customMetadata = roomData.customMetadata || {};
160
- this.admins = roomData.admins || [];
161
- this.roomCode = roomData.roomCode;
162
- this.description = roomData.description;
163
- this.data = roomData.data || {};
164
- this.version = roomData.version;
165
- console.log(`VenusRoom: Created room object for ${this.id}`, {
166
- hasCustomMetadata: !!this.customMetadata,
167
- hasGameState: !!this.customMetadata?.rules?.gameState,
168
- gamePhase: this.customMetadata?.rules?.gameState?.phase,
169
- currentPlayer: this.customMetadata?.rules?.gameState?.currentPlayer
170
- });
171
- }
172
- updateFromRoomData(newRoomData) {
173
- if (newRoomData.id === this.id) {
174
- this.name = newRoomData.name || this.name;
175
- this.players = newRoomData.currentPlayers || this.players;
176
- this.maxPlayers = newRoomData.maxPlayers || this.maxPlayers;
177
- this.gameType = newRoomData.gameType || this.gameType;
178
- this.currentPlayers = newRoomData.currentPlayers || this.currentPlayers;
179
- this.customMetadata = newRoomData.customMetadata || this.customMetadata;
180
- this.data = newRoomData.data || this.data;
181
- this.status = newRoomData.status || this.status;
182
- this.updatedAt = newRoomData.updatedAt || this.updatedAt;
183
- console.log(`VenusRoom: Updated room object ${this.id} with fresh data`, {
184
- hasCustomMetadata: !!this.customMetadata,
185
- hasGameState: !!this.customMetadata?.rules?.gameState,
186
- gamePhase: this.customMetadata?.rules?.gameState?.phase,
187
- currentPlayer: this.customMetadata?.rules?.gameState?.currentPlayer
188
- });
189
- }
190
- }
191
- };
192
- }
193
- });
194
-
195
- // src/rooms/index.ts
196
- var rooms_exports = {};
197
- __export(rooms_exports, {
198
- VenusRoom: () => VenusRoom,
199
- initializeRoomsApi: () => initializeRoomsApi,
200
- setupRoomNotifications: () => setupRoomNotifications
201
- });
202
- function bindMethod(target, targetKey, source, sourceKey) {
203
- const key = sourceKey ?? targetKey;
204
- const fn = source?.[key];
205
- if (typeof fn === "function") {
206
- target[targetKey] = fn.bind(source);
207
- return true;
208
- }
209
- return false;
210
- }
211
- function setupRoomNotifications(transport, getSubscriptions) {
212
- console.log("[Venus Rooms] Setting up room notification listeners");
213
- return transport.onVenusMessage((message) => {
214
- const subscriptions = getSubscriptions();
215
- if (!subscriptions) {
216
- return;
217
- }
218
- if (message.type === "H5_ROOM_DATA_UPDATED") {
219
- const messageData = message.data;
220
- const { roomId, roomData } = messageData;
221
- if (!roomId) return;
222
- const callbacks = subscriptions.data?.[roomId] || [];
223
- const allEventsCallbacks = subscriptions.allEvents?.[roomId] || [];
224
- console.log(`[Venus Rooms] \u{1F514} Room data updated for ${roomId}, notifying ${callbacks.length} callbacks`, roomData);
225
- callbacks.forEach((callback) => {
226
- try {
227
- callback(roomData);
228
- } catch (error) {
229
- console.error("[Venus Rooms] Error in room data callback:", error);
230
- throw error;
231
- }
232
- });
233
- allEventsCallbacks.forEach((callback) => {
234
- try {
235
- callback({ type: message.type, ...messageData });
236
- } catch (error) {
237
- console.error("[Venus Rooms] Error in allEvents callback:", error);
238
- throw error;
239
- }
240
- });
241
- }
242
- if (message.type === "H5_ROOM_MESSAGE_RECEIVED" || message.type === "H5_ROOM_MESSAGE_UPDATED" || message.type === "H5_ROOM_MESSAGE_DELETED") {
243
- const messageData = message.data;
244
- const { roomId } = messageData;
245
- if (!roomId) return;
246
- const callbacks = subscriptions.messages?.[roomId] || [];
247
- const allEventsCallbacks = subscriptions.allEvents?.[roomId] || [];
248
- console.log(`[Venus Rooms] \u{1F514} Room message event for ${roomId}, notifying ${callbacks.length} callbacks`);
249
- callbacks.forEach((callback) => {
250
- try {
251
- callback(messageData);
252
- } catch (error) {
253
- console.error("[Venus Rooms] Error in room message callback:", error);
254
- throw error;
255
- }
256
- });
257
- allEventsCallbacks.forEach((callback) => {
258
- try {
259
- callback({ type: message.type, ...messageData });
260
- } catch (error) {
261
- console.error("[Venus Rooms] Error in allEvents callback:", error);
262
- throw error;
263
- }
264
- });
265
- }
266
- if (message.type === "app:h5:proposedMoveValidationUpdated") {
267
- const messageData = message.data;
268
- const { roomId } = messageData;
269
- if (!roomId) return;
270
- const callbacks = subscriptions.gameEvents?.[roomId] || [];
271
- const allEventsCallbacks = subscriptions.allEvents?.[roomId] || [];
272
- console.log(`[Venus Rooms] \u{1F514} Proposed move validation updated for ${roomId}, notifying ${callbacks.length} callbacks`);
273
- callbacks.forEach((callback) => {
274
- try {
275
- callback(messageData);
276
- } catch (error) {
277
- console.error("[Venus Rooms] Error in game event callback:", error);
278
- throw error;
279
- }
280
- });
281
- allEventsCallbacks.forEach((callback) => {
282
- try {
283
- callback({ type: message.type, ...messageData });
284
- } catch (error) {
285
- console.error("[Venus Rooms] Error in allEvents callback:", error);
286
- throw error;
287
- }
288
- });
289
- }
290
- });
291
- }
292
- function initializeRoomsApi(venusApi, host) {
293
- const roomsApi = host?.rooms;
294
- if (!roomsApi) {
295
- console.warn(
296
- "[Venus SDK] Host did not provide a rooms implementation. Rooms API will be unavailable."
297
- );
298
- return;
299
- }
300
- const venus = venusApi;
301
- const existingNamespace = venus.rooms || {};
302
- const roomsNamespace = Object.assign({}, existingNamespace);
303
- const namespaceBindings = [
304
- ["create", "createRoom"],
305
- ["joinOrCreate", "joinOrCreateRoom"],
306
- ["joinByCode", "joinRoomByCode"],
307
- ["list", "getUserRooms"],
308
- ["subscribeToRoom", "subscribe"],
309
- ["updateRoomData", "updateData"],
310
- ["getRoomData", "getData"],
311
- ["sendRoomMessage", "sendMessage"],
312
- ["leaveRoom", "leave"],
313
- ["startRoomGame", "startGame"],
314
- ["proposeMove"],
315
- ["validateMove"]
316
- ];
317
- namespaceBindings.forEach(([targetKey, sourceKey]) => {
318
- bindMethod(roomsNamespace, targetKey, roomsApi, sourceKey);
319
- });
320
- venus.rooms = roomsNamespace;
321
- }
322
- var init_rooms = __esm({
323
- "src/rooms/index.ts"() {
324
- init_RoomsApi();
325
- init_VenusRoom();
326
- }
327
- });
328
-
329
103
  // src/storage/MockStorageApi.ts
330
104
  function createMockStorageApi(storageType, appUrl) {
331
105
  const appIdentifier = appUrl ? generateAppIdentifier(appUrl) : null;
@@ -635,190 +409,6 @@ function initializeAds(venusApiInstance, host) {
635
409
  venusApiInstance.ads = host.ads;
636
410
  }
637
411
 
638
- // src/venus-api/systems/theme.js
639
- init_core();
640
- var DEFAULT_TYPOGRAPHY = {
641
- fontFamily: {
642
- base: "Plus Jakarta Sans, Roboto, sans-serif",
643
- heading: "Plus Jakarta Sans, Roboto, sans-serif",
644
- mono: "monospace"
645
- },
646
- fontSize: {
647
- "2xs": "10px",
648
- xs: "12px",
649
- sm: "14px",
650
- md: "16px",
651
- lg: "18px",
652
- xl: "20px",
653
- "2xl": "24px",
654
- "3xl": "30px",
655
- "4xl": "36px",
656
- "5xl": "48px",
657
- "6xl": "60px"
658
- },
659
- fontWeight: {
660
- thin: "100",
661
- extralight: "200",
662
- light: "300",
663
- regular: "400",
664
- medium: "500",
665
- semibold: "600",
666
- bold: "700",
667
- extrabold: "800",
668
- black: "900",
669
- extrablack: "950"
670
- },
671
- lineHeight: {
672
- none: "1",
673
- tight: "1.25",
674
- snug: "1.375",
675
- normal: "1.5",
676
- relaxed: "1.625",
677
- loose: "2"
678
- }
679
- };
680
- var DEFAULT_THEME = {
681
- background: {
682
- default: "#131419",
683
- // Dark background
684
- muted: "#1b1d25",
685
- // Mid-dark background
686
- dark: "#0d0e11"
687
- // Darker background
688
- },
689
- text: {
690
- primary: "#ffffff",
691
- // White
692
- muted: "#808080",
693
- // Gray
694
- inverted: "#000000"
695
- // Black
696
- },
697
- theme: {
698
- primary: "#f6c833",
699
- // Different yellow for testing (slightly lighter)
700
- secondary: "#6366f1",
701
- // Different secondary for testing (purple)
702
- background: "#131419",
703
- // Dark background
704
- border: "#262626",
705
- // Dark border
706
- card: "#1b1d25",
707
- // Dark card
708
- "card-glass": "rgba(27, 29, 37, 0.8)"
709
- // Translucent dark card
710
- },
711
- typography: DEFAULT_TYPOGRAPHY
712
- };
713
- function initializeTheme(venusApiInstance) {
714
- if (!venusApiInstance._mock.theme) {
715
- venusApiInstance._mock.theme = DEFAULT_THEME;
716
- }
717
- if (!venusApiInstance._mock.typography) {
718
- venusApiInstance._mock.typography = DEFAULT_TYPOGRAPHY;
719
- }
720
- if (!venusApiInstance._mock.safeArea) {
721
- venusApiInstance._mock.safeArea = { top: 0, bottom: 0, left: 0, right: 0 };
722
- }
723
- venusApiInstance.applyVenusThemeToCSS = function(theme) {
724
- if (!theme) return;
725
- const root = document.documentElement;
726
- if (theme.background) {
727
- if (theme.background.default)
728
- root.style.setProperty("--color-background", theme.background.default);
729
- if (theme.background.muted)
730
- root.style.setProperty(
731
- "--color-background-muted",
732
- theme.background.muted
733
- );
734
- if (theme.background.dark)
735
- root.style.setProperty(
736
- "--color-background-dark",
737
- theme.background.dark
738
- );
739
- }
740
- if (theme.text) {
741
- if (theme.text.primary)
742
- root.style.setProperty("--color-text-primary", theme.text.primary);
743
- if (theme.text.muted)
744
- root.style.setProperty("--color-text-muted", theme.text.muted);
745
- }
746
- if (theme.theme) {
747
- if (theme.theme.primary)
748
- root.style.setProperty("--color-primary", theme.theme.primary);
749
- if (theme.theme.secondary)
750
- root.style.setProperty("--color-secondary", theme.theme.secondary);
751
- if (theme.theme.border)
752
- root.style.setProperty("--color-border", theme.theme.border);
753
- }
754
- if (theme.typography && theme.typography.fontFamily) {
755
- if (theme.typography.fontFamily.base) {
756
- root.style.setProperty(
757
- "--font-family",
758
- theme.typography.fontFamily.base
759
- );
760
- }
761
- }
762
- document.body.style.backgroundColor = root.style.getPropertyValue(
763
- "--color-background-dark"
764
- );
765
- };
766
- venusApiInstance.applyTheme = createProxiedMethod("applyTheme", function() {
767
- let apiTheme = null;
768
- apiTheme = this.config.theme;
769
- if (apiTheme) {
770
- this.applyVenusThemeToCSS(apiTheme);
771
- this.colors = {
772
- primary: apiTheme.theme?.primary || "#FF2877",
773
- secondary: apiTheme.theme?.secondary || "#4755FF",
774
- dark: apiTheme.background?.dark || "#0D0E11",
775
- darkLight: apiTheme.background?.muted || "#1B1D25",
776
- darkLighter: apiTheme.background?.default || "#23252F",
777
- textPrimary: apiTheme.text?.primary || "#FFFFFF",
778
- textMuted: apiTheme.text?.muted || "#808080",
779
- border: apiTheme.theme?.border || "#262626"
780
- };
781
- } else {
782
- this.colors = {
783
- primary: "#FF2877",
784
- secondary: "#4755FF",
785
- dark: "#0D0E11",
786
- darkLight: "#1B1D25",
787
- darkLighter: "#23252F",
788
- textPrimary: "#FFFFFF",
789
- textMuted: "#808080",
790
- border: "#262626"
791
- };
792
- }
793
- this.log("Theme applied successfully");
794
- });
795
- venusApiInstance.applySafeArea = createProxiedMethod("applySafeArea", function() {
796
- try {
797
- const safeArea = this.config.ui.safeArea;
798
- if (safeArea) {
799
- this.log("Applying safe area insets: " + JSON.stringify(safeArea));
800
- if (this.tapToStartScreen) {
801
- this.tapToStartScreen.style.marginTop = `${safeArea.top}px`;
802
- this.tapToStartScreen.style.marginBottom = `${safeArea.bottom}px`;
803
- }
804
- if (this.gameOverScreen) {
805
- this.gameOverScreen.style.marginTop = `${safeArea.top}px`;
806
- this.gameOverScreen.style.marginBottom = `${safeArea.bottom}px`;
807
- }
808
- if (this.maxScoreContainer) {
809
- this.maxScoreContainer.style.marginTop = `${safeArea.top}px`;
810
- this.maxScoreContainer.style.marginRight = `${safeArea.right}px`;
811
- }
812
- }
813
- } catch (error) {
814
- this.error("Error applying safe area: " + error.message);
815
- console.error("Error applying safe area:", error);
816
- }
817
- });
818
- venusApiInstance.DEFAULT_THEME = DEFAULT_THEME;
819
- venusApiInstance.DEFAULT_TYPOGRAPHY = DEFAULT_TYPOGRAPHY;
820
- }
821
-
822
412
  // src/popups/RpcPopupsApi.ts
823
413
  var RpcPopupsApi = class {
824
414
  constructor(rpcClient) {
@@ -971,13 +561,8 @@ var MockNotificationsApi = class {
971
561
  async cancelNotification(notificationId) {
972
562
  const venusApi = this.venusApi;
973
563
  if (isWebPlatform()) {
974
- console.log(
975
- "[Venus Mock] Cancel notification on web platform (simulated):",
976
- notificationId
977
- );
978
564
  return true;
979
565
  }
980
- console.log("[Venus Mock] Cancel local notification:", notificationId);
981
566
  await createMockDelay(MOCK_DELAYS.short);
982
567
  if (venusApi._mock.scheduledNotifications && venusApi._mock.scheduledNotifications[notificationId]) {
983
568
  delete venusApi._mock.scheduledNotifications[notificationId];
@@ -987,12 +572,8 @@ var MockNotificationsApi = class {
987
572
  }
988
573
  async getAllScheduledLocalNotifications() {
989
574
  if (isWebPlatform()) {
990
- console.log(
991
- "[Venus Mock] Get notifications on web platform (returning empty list)"
992
- );
993
575
  return [];
994
576
  }
995
- console.log("[Venus Mock] Get all scheduled local notifications");
996
577
  await createMockDelay(MOCK_DELAYS.short);
997
578
  const venusApi = this.venusApi;
998
579
  const notifications = venusApi._mock.scheduledNotifications || {};
@@ -1000,10 +581,8 @@ var MockNotificationsApi = class {
1000
581
  }
1001
582
  async isLocalNotificationsEnabled() {
1002
583
  if (isWebPlatform()) {
1003
- console.log("[Venus Mock] Notifications not available on web platform");
1004
584
  return false;
1005
585
  }
1006
- console.log("[Venus Mock] Check if local notifications are enabled");
1007
586
  await createMockDelay(MOCK_DELAYS.short);
1008
587
  const venusApi = this.venusApi;
1009
588
  const isEnabled = venusApi._mock.notificationsEnabled !== false;
@@ -1012,9 +591,6 @@ var MockNotificationsApi = class {
1012
591
  async scheduleAsync(title, body, seconds, notificationId, options) {
1013
592
  const { priority = 50, groupId, payload } = options || {};
1014
593
  if (isWebPlatform()) {
1015
- console.log(
1016
- "[Venus Mock] Notifications not supported on web platform, simulating success"
1017
- );
1018
594
  console.info(
1019
595
  "\u{1F514} [Venus Mock] Notification would be scheduled:",
1020
596
  title || "Untitled",
@@ -1025,14 +601,11 @@ var MockNotificationsApi = class {
1025
601
  const mockId = `mock-web-notification-${Date.now()}`;
1026
602
  return mockId;
1027
603
  }
1028
- console.log("[Venus Mock] Schedule local notification:", { title, body, seconds, options });
1029
604
  const venusApi = this.venusApi;
1030
605
  if (!venusApi._mock.pendingRequests) {
1031
- console.log("[Venus Mock] Initializing pendingRequests");
1032
606
  venusApi._mock.pendingRequests = {};
1033
607
  }
1034
608
  const requestId = Date.now().toString();
1035
- console.log("[Venus Mock] Creating request with ID:", requestId);
1036
609
  return new Promise((resolve) => {
1037
610
  venusApi._mock.pendingRequests[requestId] = { resolve };
1038
611
  const id = notificationId || `mock-notification-${Date.now()}`;
@@ -1054,13 +627,8 @@ var MockNotificationsApi = class {
1054
627
  async setLocalNotificationsEnabled(enabled) {
1055
628
  const venusApi = this.venusApi;
1056
629
  if (isWebPlatform()) {
1057
- console.log(
1058
- "[Venus Mock] Set notifications enabled on web platform (simulated):",
1059
- enabled
1060
- );
1061
630
  return true;
1062
631
  }
1063
- console.log("[Venus Mock] Set local notifications enabled:", enabled);
1064
632
  await createMockDelay(MOCK_DELAYS.short);
1065
633
  venusApi._mock.notificationsEnabled = enabled;
1066
634
  return enabled;
@@ -1157,9 +725,11 @@ function isPacificDaylightTime(date) {
1157
725
 
1158
726
  // src/time/HostTimeApi.ts
1159
727
  var HostTimeApi = class {
1160
- constructor(rpcClient) {
728
+ constructor(rpcClient, venusApi) {
1161
729
  __publicField(this, "rpcClient");
730
+ __publicField(this, "venusApi");
1162
731
  this.rpcClient = rpcClient;
732
+ this.venusApi = venusApi;
1163
733
  }
1164
734
  async requestTimeAsync() {
1165
735
  const response = await this.rpcClient.call(
@@ -1169,13 +739,7 @@ var HostTimeApi = class {
1169
739
  return response;
1170
740
  }
1171
741
  formatTime(timestamp, options) {
1172
- let locale = "en-US";
1173
- const windowVenus = window.venus;
1174
- if (windowVenus._config.locale) {
1175
- locale = windowVenus._config.locale;
1176
- } else if (windowVenus._config.environment && windowVenus._config.environment.browserInfo && windowVenus._config.environment.browserInfo.language) {
1177
- locale = windowVenus._config.environment.browserInfo.language;
1178
- }
742
+ const locale = this.venusApi.getLocale();
1179
743
  const date = new Date(timestamp);
1180
744
  const dateTimeOptions = {
1181
745
  dateStyle: options.dateStyle || "medium",
@@ -1187,13 +751,7 @@ var HostTimeApi = class {
1187
751
  }
1188
752
  formatNumber(value, options) {
1189
753
  try {
1190
- let locale = "en-US";
1191
- const windowVenus = window.venus;
1192
- if (windowVenus._config.locale) {
1193
- locale = windowVenus._config.locale;
1194
- } else if (windowVenus._config.environment && windowVenus._config.environment.browserInfo && windowVenus._config.environment.browserInfo.language) {
1195
- locale = windowVenus._config.environment.browserInfo.language;
1196
- }
754
+ const locale = this.venusApi.getLocale();
1197
755
  const numberOptions = {
1198
756
  style: options?.style || "decimal",
1199
757
  minimumFractionDigits: options?.minimumFractionDigits || 0,
@@ -1257,18 +815,17 @@ var MockTimeApi = class {
1257
815
  this.venusApi = venusApi;
1258
816
  }
1259
817
  formatNumber(value, options) {
1260
- const locale = this.getLocale();
818
+ const locale = this.venusApi.getLocale();
1261
819
  const numberOptions = {
1262
820
  style: options?.style || "decimal",
1263
821
  minimumFractionDigits: options?.minimumFractionDigits || 0,
1264
822
  maximumFractionDigits: options?.maximumFractionDigits || 2,
1265
823
  ...options
1266
824
  };
1267
- console.log(`[Venus Mock] Formatting number ${value} with locale ${locale}`);
1268
825
  return value.toLocaleString(locale, numberOptions);
1269
826
  }
1270
827
  formatTime(timestamp, options) {
1271
- const locale = this.getLocale();
828
+ const locale = this.venusApi.getLocale();
1272
829
  const date = new Date(timestamp);
1273
830
  const dateTimeOptions = {
1274
831
  dateStyle: options.dateStyle || "medium",
@@ -1276,13 +833,9 @@ var MockTimeApi = class {
1276
833
  hour12: options.hour12 !== void 0 ? options.hour12 : true,
1277
834
  ...options
1278
835
  };
1279
- console.log(
1280
- `[Venus Mock] Formatting time ${timestamp} with locale ${locale}`
1281
- );
1282
836
  return date.toLocaleString(locale, dateTimeOptions);
1283
837
  }
1284
838
  async getFutureTimeAsync(options) {
1285
- console.log("[Venus Mock] Getting future time with options:", options);
1286
839
  const timeInfo = await this.requestTimeAsync();
1287
840
  const serverTime = new Date(timeInfo.serverTime);
1288
841
  const result = new Date(serverTime);
@@ -1327,7 +880,6 @@ var MockTimeApi = class {
1327
880
  return result.getTime();
1328
881
  }
1329
882
  async requestTimeAsync() {
1330
- console.log("[Venus Mock] Requesting time");
1331
883
  await createMockDelay(MOCK_DELAYS.short);
1332
884
  const venusApi = this.venusApi;
1333
885
  const mockOffset = venusApi._mock.serverTimeOffset || 2500;
@@ -1341,23 +893,8 @@ var MockTimeApi = class {
1341
893
  formattedTime: new Date(localTime).toISOString(),
1342
894
  locale: venusApi._mock.user?.locale || "en-US"
1343
895
  };
1344
- console.log("[Venus Mock] Time response:", {
1345
- serverTime: new Date(timeInfo.serverTime).toISOString(),
1346
- localTime: new Date(timeInfo.localTime).toISOString(),
1347
- timezoneOffset: timeInfo.timezoneOffset
1348
- });
1349
896
  return timeInfo;
1350
897
  }
1351
- getLocale() {
1352
- const venusApi = this.venusApi;
1353
- let locale = "en-US";
1354
- if (venusApi._mock.user && venusApi._mock.user.locale) {
1355
- locale = venusApi._mock.user.locale;
1356
- } else if (venusApi._mock.environment && venusApi._mock.environment.browserInfo.language) {
1357
- locale = venusApi._mock.environment.browserInfo.language;
1358
- }
1359
- return locale;
1360
- }
1361
898
  };
1362
899
 
1363
900
  // src/time/index.ts
@@ -1392,7 +929,7 @@ var MockAvatarApi = class {
1392
929
  async deleteAvatar() {
1393
930
  console.log(`[Venus Mock] Deleting avatar3d config`);
1394
931
  const venusApi = this._venusApi;
1395
- const currentProfile = venusApi.getCurrentProfile();
932
+ const currentProfile = venusApi.getProfile();
1396
933
  const profileId = currentProfile?.id || "default_profile";
1397
934
  localStorage.removeItem(`venus-mock-avatar3d-${profileId}`);
1398
935
  console.log(
@@ -1407,7 +944,7 @@ var MockAvatarApi = class {
1407
944
  console.log(`[Venus Mock] Loading shared avatar3d by ID: ${avatar3dId}`);
1408
945
  config = await this.selectAvatarConfig(avatar3dId, false);
1409
946
  } else {
1410
- const currentProfile = venusApi.getCurrentProfile();
947
+ const currentProfile = venusApi.getProfile();
1411
948
  const profileId = currentProfile?.id || "default_profile";
1412
949
  console.log(`[Venus Mock] Loading avatar3d for profile: ${profileId}`);
1413
950
  console.log(
@@ -1424,7 +961,7 @@ var MockAvatarApi = class {
1424
961
  async saveAvatar(config) {
1425
962
  console.log(`[Venus Mock] Saving avatar3d config:`, config);
1426
963
  const venusApi = this._venusApi;
1427
- const currentProfile = venusApi.getCurrentProfile();
964
+ const currentProfile = venusApi.getProfile();
1428
965
  const profileId = currentProfile?.id || "default_profile";
1429
966
  localStorage.setItem(
1430
967
  `venus-mock-avatar3d-${profileId}`,
@@ -2085,7 +1622,7 @@ var VenusAssetLoader = class {
2085
1622
  // Set the VenusAPI reference during initialization
2086
1623
  setVenusAPI(api) {
2087
1624
  this.venusAPI = api;
2088
- this.isWebView = !api.isWeb || !api.isWeb();
1625
+ this.isWebView = typeof window !== "undefined" && typeof window.ReactNativeWebView !== "undefined";
2089
1626
  }
2090
1627
  /**
2091
1628
  * Load any asset with automatic optimization
@@ -2206,14 +1743,11 @@ var VenusAssetLoader = class {
2206
1743
  }, 1e4);
2207
1744
  if (type === "image") {
2208
1745
  const img = new Image();
2209
- console.log(`\u{1F5BC}\uFE0F [Asset Verification] Verifying image: ${url}`);
2210
1746
  img.onload = () => {
2211
- console.log(`\u2705 [Asset Verification] Image verified successfully: ${url}`);
2212
1747
  clearTimeout(timeout);
2213
1748
  resolve();
2214
1749
  };
2215
1750
  img.onerror = (error) => {
2216
- console.log(`\u274C [Asset Verification] Image verification failed: ${url}`, error);
2217
1751
  clearTimeout(timeout);
2218
1752
  reject(new Error("Failed to load image"));
2219
1753
  };
@@ -2265,7 +1799,6 @@ var VenusAssetLoader = class {
2265
1799
  const CDN_BASE_URL = "https://venus-static-01293ak.web.app/";
2266
1800
  const cleanUrl = url.startsWith("/") ? url.slice(1) : url;
2267
1801
  const fullUrl = CDN_BASE_URL + cleanUrl;
2268
- console.log(`\u{1F310} [Asset Loader] Force remote CDN: ${url} -> ${fullUrl}`);
2269
1802
  return fullUrl;
2270
1803
  }
2271
1804
  if (this.venusAPI && this.venusAPI.isMock && this.venusAPI.isMock()) {
@@ -3976,47 +3509,105 @@ function initializeIap(venusApiInstance, host) {
3976
3509
  venusApiInstance.iap = host.iap;
3977
3510
  }
3978
3511
 
3512
+ // src/leaderboard/utils.ts
3513
+ var HASH_ALGORITHM_WEB_CRYPTO = "SHA-256";
3514
+ async function computeScoreHash(score, duration, token, sealingNonce, sealingSecret) {
3515
+ const payload = `score:${score}|duration:${duration}|token:${token}`;
3516
+ const fullPayload = `${payload}|nonce:${sealingNonce}`;
3517
+ const encoder = new TextEncoder();
3518
+ const keyData = encoder.encode(sealingSecret);
3519
+ const messageData = encoder.encode(fullPayload);
3520
+ const cryptoKey = await crypto.subtle.importKey(
3521
+ "raw",
3522
+ keyData,
3523
+ { name: "HMAC", hash: HASH_ALGORITHM_WEB_CRYPTO },
3524
+ false,
3525
+ ["sign"]
3526
+ );
3527
+ const signature = await crypto.subtle.sign("HMAC", cryptoKey, messageData);
3528
+ return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
3529
+ }
3530
+
3979
3531
  // src/leaderboard/RpcLeaderboardApi.ts
3980
3532
  var RpcLeaderboardApi = class {
3981
3533
  constructor(rpcClient) {
3982
3534
  __publicField(this, "rpcClient");
3535
+ /** Cache of score tokens for automatic hash computation */
3536
+ __publicField(this, "tokenCache", /* @__PURE__ */ new Map());
3983
3537
  this.rpcClient = rpcClient;
3984
3538
  }
3985
- startRun(mode) {
3986
- return this.rpcClient.call(
3987
- "H5_LEADERBOARD_START_RUN" /* H5_LEADERBOARD_START_RUN */,
3539
+ /**
3540
+ * Create a score token for submitting a score.
3541
+ * Token is cached for automatic hash computation if score sealing is enabled.
3542
+ *
3543
+ * @param mode - Optional game mode
3544
+ * @returns Score token with sealing data if enabled
3545
+ */
3546
+ async createScoreToken(mode) {
3547
+ const token = await this.rpcClient.call(
3548
+ "H5_LEADERBOARD_CREATE_SCORE_TOKEN" /* H5_LEADERBOARD_CREATE_SCORE_TOKEN */,
3988
3549
  mode ? { mode } : {}
3989
3550
  );
3551
+ this.tokenCache.set(token.token, token);
3552
+ return token;
3990
3553
  }
3991
- submitScore(sessionId, score, durationSec, options) {
3554
+ /**
3555
+ * Submit a score to the leaderboard.
3556
+ * Automatically computes hash if score sealing is enabled and token was created via createScoreToken().
3557
+ *
3558
+ * @param params - Score submission parameters
3559
+ * @returns Submission result with acceptance status and rank
3560
+ * @throws Error if token not found in cache
3561
+ */
3562
+ async submitScore(params) {
3563
+ let hash;
3564
+ if (params.token) {
3565
+ const cachedToken = this.tokenCache.get(params.token);
3566
+ if (!cachedToken) {
3567
+ throw new Error(
3568
+ "Invalid token: not found in cache. Did you call createScoreToken() first?"
3569
+ );
3570
+ }
3571
+ if (cachedToken.sealingNonce && cachedToken.sealingSecret) {
3572
+ hash = await computeScoreHash(
3573
+ params.score,
3574
+ params.duration,
3575
+ params.token,
3576
+ cachedToken.sealingNonce,
3577
+ cachedToken.sealingSecret
3578
+ );
3579
+ }
3580
+ this.tokenCache.delete(params.token);
3581
+ }
3992
3582
  return this.rpcClient.call(
3993
3583
  "H5_LEADERBOARD_SUBMIT_SCORE" /* H5_LEADERBOARD_SUBMIT_SCORE */,
3994
3584
  {
3995
- sessionId,
3996
- score,
3997
- durationSec,
3998
- mode: options?.mode,
3999
- telemetry: options?.telemetry,
4000
- metadata: options?.metadata,
4001
- hash: options?.hash
3585
+ token: params.token,
3586
+ score: params.score,
3587
+ duration: params.duration,
3588
+ mode: params.mode,
3589
+ telemetry: params.telemetry,
3590
+ metadata: params.metadata,
3591
+ hash
3592
+ // undefined if no sealing, computed if sealing enabled
4002
3593
  }
4003
3594
  );
4004
3595
  }
4005
- getLeaderboard(options) {
3596
+ getPagedScores(options) {
4006
3597
  return this.rpcClient.call(
4007
- "H5_LEADERBOARD_GET" /* H5_LEADERBOARD_GET */,
3598
+ "H5_LEADERBOARD_GET_PAGED_SCORES" /* H5_LEADERBOARD_GET_PAGED_SCORES */,
4008
3599
  options ?? {}
4009
3600
  );
4010
3601
  }
4011
- getPlayerStats(options) {
3602
+ getMyRank(options) {
4012
3603
  return this.rpcClient.call(
4013
- "H5_LEADERBOARD_GET_PLAYER_STATS" /* H5_LEADERBOARD_GET_PLAYER_STATS */,
3604
+ "H5_LEADERBOARD_GET_MY_RANK" /* H5_LEADERBOARD_GET_MY_RANK */,
4014
3605
  options ?? {}
4015
3606
  );
4016
3607
  }
4017
- getLeaderboardHighlight(options) {
3608
+ getPodiumScores(options) {
4018
3609
  return this.rpcClient.call(
4019
- "H5_LEADERBOARD_GET_HIGHLIGHT" /* H5_LEADERBOARD_GET_HIGHLIGHT */,
3610
+ "H5_LEADERBOARD_GET_PODIUM_SCORES" /* H5_LEADERBOARD_GET_PODIUM_SCORES */,
4020
3611
  options ?? {}
4021
3612
  );
4022
3613
  }
@@ -4025,17 +3616,31 @@ var RpcLeaderboardApi = class {
4025
3616
  // src/leaderboard/MockLeaderboardApi.ts
4026
3617
  var MockLeaderboardApi = class {
4027
3618
  constructor(options) {
4028
- __publicField(this, "sessions", /* @__PURE__ */ new Map());
3619
+ __publicField(this, "tokens", /* @__PURE__ */ new Map());
3620
+ /** Cache of score tokens for automatic hash computation */
3621
+ __publicField(this, "tokenCache", /* @__PURE__ */ new Map());
4029
3622
  __publicField(this, "entriesByMode", /* @__PURE__ */ new Map());
4030
- __publicField(this, "sessionCounter", 0);
4031
- __publicField(this, "requiresHash", false);
4032
- if (options?.requiresHash) {
4033
- this.requiresHash = true;
3623
+ __publicField(this, "tokenCounter", 0);
3624
+ __publicField(this, "enableScoreSealing", false);
3625
+ __publicField(this, "scoreSealingSecret", "mock-leaderboard-secret-key");
3626
+ if (options?.enableScoreSealing) {
3627
+ this.enableScoreSealing = true;
3628
+ }
3629
+ if (options?.scoreSealingSecret) {
3630
+ this.scoreSealingSecret = options.scoreSealingSecret;
4034
3631
  }
4035
3632
  }
3633
+ /**
3634
+ * Configure mock leaderboard settings
3635
+ *
3636
+ * @param options - Configuration options
3637
+ */
4036
3638
  configure(options) {
4037
- if (typeof options.requiresHash === "boolean") {
4038
- this.requiresHash = options.requiresHash;
3639
+ if (typeof options.enableScoreSealing === "boolean") {
3640
+ this.enableScoreSealing = options.enableScoreSealing;
3641
+ }
3642
+ if (options.scoreSealingSecret) {
3643
+ this.scoreSealingSecret = options.scoreSealingSecret;
4039
3644
  }
4040
3645
  }
4041
3646
  generateNonce() {
@@ -4052,83 +3657,149 @@ var MockLeaderboardApi = class {
4052
3657
  }
4053
3658
  return this.entriesByMode.get(key);
4054
3659
  }
4055
- async startRun(mode) {
4056
- const sessionId = `mock_session_${++this.sessionCounter}`;
3660
+ /**
3661
+ * Create a mock score token for testing.
3662
+ * Token is cached for automatic hash computation if score sealing is enabled.
3663
+ *
3664
+ * @param mode - Optional game mode
3665
+ * @returns Score token with sealing data if enabled
3666
+ */
3667
+ async createScoreToken(mode) {
3668
+ const token = `mock_token_${++this.tokenCounter}`;
4057
3669
  const startTime = Date.now();
4058
3670
  const expiresAt = startTime + 36e5;
4059
3671
  const resolvedMode = mode || "default";
4060
- const hashNonce = this.requiresHash ? this.generateNonce() : null;
4061
- this.sessions.set(sessionId, {
4062
- id: sessionId,
3672
+ const sealingNonce = this.enableScoreSealing ? this.generateNonce() : null;
3673
+ const sealingSecret = this.enableScoreSealing ? this.scoreSealingSecret : null;
3674
+ this.tokens.set(token, {
3675
+ id: token,
4063
3676
  expiresAt,
4064
3677
  mode: resolvedMode,
4065
- hashNonce,
3678
+ sealingNonce,
4066
3679
  used: false
4067
3680
  });
4068
- return {
4069
- sessionId,
3681
+ const result = {
3682
+ token,
4070
3683
  startTime,
4071
3684
  expiresAt,
4072
- hashNonce,
3685
+ sealingNonce,
3686
+ sealingSecret,
4073
3687
  mode: resolvedMode
4074
3688
  };
3689
+ this.tokenCache.set(token, result);
3690
+ return result;
4075
3691
  }
4076
- async submitScore(sessionId, score, durationSec, options) {
4077
- const session = this.sessions.get(sessionId);
4078
- if (!session) {
4079
- throw new Error("Invalid leaderboard session");
3692
+ /**
3693
+ * Submit a mock score to the leaderboard.
3694
+ * Automatically computes hash if score sealing is enabled and token was created via createScoreToken().
3695
+ *
3696
+ * @param params - Score submission parameters
3697
+ * @returns Submission result with acceptance status and rank
3698
+ * @throws Error if token not found in cache or validation fails
3699
+ */
3700
+ async submitScore(params) {
3701
+ let hash;
3702
+ if (params.token) {
3703
+ const cachedToken = this.tokenCache.get(params.token);
3704
+ if (!cachedToken) {
3705
+ throw new Error(
3706
+ "Invalid token: not found in cache. Did you call createScoreToken() first?"
3707
+ );
3708
+ }
3709
+ if (cachedToken.sealingNonce && cachedToken.sealingSecret) {
3710
+ hash = await computeScoreHash(
3711
+ params.score,
3712
+ params.duration,
3713
+ params.token,
3714
+ cachedToken.sealingNonce,
3715
+ cachedToken.sealingSecret
3716
+ );
3717
+ }
3718
+ }
3719
+ if (!params.token) {
3720
+ const mode = params.mode || "default";
3721
+ const submittedAt2 = Date.now();
3722
+ const entry2 = {
3723
+ profileId: `mock_profile`,
3724
+ username: "Mock Player",
3725
+ avatarUrl: null,
3726
+ score: params.score,
3727
+ duration: params.duration,
3728
+ submittedAt: submittedAt2,
3729
+ token: "simple-mode",
3730
+ rank: null,
3731
+ zScore: null,
3732
+ isAnomaly: false,
3733
+ trustScore: 50,
3734
+ metadata: params.metadata ?? null,
3735
+ isSeed: false
3736
+ };
3737
+ const modeEntries2 = this.getEntriesForMode(mode);
3738
+ modeEntries2.push(entry2);
3739
+ modeEntries2.sort((a, b) => {
3740
+ if (b.score !== a.score) return b.score - a.score;
3741
+ return a.submittedAt - b.submittedAt;
3742
+ });
3743
+ modeEntries2.forEach((e, index) => {
3744
+ modeEntries2[index] = { ...e, rank: index + 1 };
3745
+ });
3746
+ const inserted2 = modeEntries2.find((e) => e.submittedAt === submittedAt2);
3747
+ return {
3748
+ accepted: true,
3749
+ rank: inserted2?.rank ?? null
3750
+ };
3751
+ }
3752
+ const scoreToken = this.tokens.get(params.token);
3753
+ if (!scoreToken) {
3754
+ throw new Error("Invalid score token");
4080
3755
  }
4081
- if (session.expiresAt < Date.now()) {
4082
- throw new Error("Invalid or expired leaderboard session");
3756
+ if (scoreToken.expiresAt < Date.now()) {
3757
+ throw new Error("Invalid or expired score token");
4083
3758
  }
4084
- if (session.used) {
4085
- throw new Error("Leaderboard session already used");
3759
+ if (scoreToken.used) {
3760
+ throw new Error("Score token already used");
4086
3761
  }
4087
- if (options?.mode && options.mode !== session.mode) {
4088
- throw new Error("Submission mode does not match session mode");
3762
+ if (params.mode && params.mode !== scoreToken.mode) {
3763
+ throw new Error("Submission mode does not match token mode");
4089
3764
  }
4090
- if (session.hashNonce && !options?.hash) {
4091
- throw new Error("Score hash is required for sealed leaderboard submissions");
3765
+ if (scoreToken.sealingNonce && !hash) {
3766
+ throw new Error("Score hash required when score sealing is enabled");
4092
3767
  }
4093
3768
  const submittedAt = Date.now();
4094
3769
  const entry = {
4095
3770
  profileId: `mock_profile`,
4096
3771
  username: "Mock Player",
4097
3772
  avatarUrl: null,
4098
- score,
4099
- durationSec,
3773
+ score: params.score,
3774
+ duration: params.duration,
4100
3775
  submittedAt,
4101
- sessionId,
3776
+ token: params.token,
4102
3777
  rank: null,
4103
3778
  zScore: null,
4104
3779
  isAnomaly: false,
4105
3780
  trustScore: 50,
4106
- metadata: options?.metadata ?? null,
3781
+ metadata: params.metadata ?? null,
4107
3782
  isSeed: false
4108
3783
  };
4109
- const modeEntries = this.getEntriesForMode(session.mode);
3784
+ const modeEntries = this.getEntriesForMode(scoreToken.mode);
4110
3785
  modeEntries.push(entry);
4111
3786
  modeEntries.sort((a, b) => {
4112
- if (b.score !== a.score) {
4113
- return b.score - a.score;
4114
- }
3787
+ if (b.score !== a.score) return b.score - a.score;
4115
3788
  return a.submittedAt - b.submittedAt;
4116
3789
  });
4117
3790
  modeEntries.forEach((e, index) => {
4118
- modeEntries[index] = {
4119
- ...e,
4120
- rank: index + 1
4121
- };
3791
+ modeEntries[index] = { ...e, rank: index + 1 };
4122
3792
  });
4123
- session.used = true;
4124
- session.hashNonce = null;
4125
- const inserted = modeEntries.find((e) => e.sessionId === sessionId && e.submittedAt === submittedAt);
3793
+ scoreToken.used = true;
3794
+ scoreToken.sealingNonce = null;
3795
+ this.tokenCache.delete(params.token);
3796
+ const inserted = modeEntries.find((e) => e.token === params.token && e.submittedAt === submittedAt);
4126
3797
  return {
4127
3798
  accepted: true,
4128
3799
  rank: inserted?.rank ?? null
4129
3800
  };
4130
3801
  }
4131
- async getLeaderboard(options) {
3802
+ async getPagedScores(options) {
4132
3803
  const limit = options?.limit ?? 10;
4133
3804
  const mode = options?.mode ?? "default";
4134
3805
  const modeEntries = [...this.getEntriesForMode(mode)];
@@ -4144,7 +3815,7 @@ var MockLeaderboardApi = class {
4144
3815
  periodInstance: options?.period ?? "alltime"
4145
3816
  };
4146
3817
  }
4147
- async getPlayerStats(_options) {
3818
+ async getMyRank(_options) {
4148
3819
  const mode = _options?.mode ?? "default";
4149
3820
  const modeEntries = this.getEntriesForMode(mode);
4150
3821
  const playerEntry = modeEntries[0] ?? null;
@@ -4157,7 +3828,7 @@ var MockLeaderboardApi = class {
4157
3828
  periodInstance: _options?.period ?? "alltime"
4158
3829
  };
4159
3830
  }
4160
- async getLeaderboardHighlight(options) {
3831
+ async getPodiumScores(options) {
4161
3832
  const mode = options?.mode ?? "default";
4162
3833
  const modeEntries = [...this.getEntriesForMode(mode)];
4163
3834
  const topCount = Math.max(1, Math.min(options?.topCount ?? 3, 10));
@@ -4210,16 +3881,20 @@ function initializeLeaderboard(venusApiInstance, host) {
4210
3881
 
4211
3882
  // src/profile/HostProfileApi.ts
4212
3883
  var HostProfileApi = class {
3884
+ constructor(venusApi) {
3885
+ __publicField(this, "venusApi");
3886
+ this.venusApi = venusApi;
3887
+ }
4213
3888
  getCurrentProfile() {
4214
- const profile = window.venus?.profile;
3889
+ const profile = this.venusApi._profileData;
4215
3890
  if (!profile) {
4216
3891
  throw new Error(
4217
- "[Venus SDK] Host profile handshake did not complete. Await VenusAPI.initializeAsync() so INIT_SDK can deliver the profile before calling profile APIs."
3892
+ "[Venus SDK] Profile not available. You must await VenusAPI.initializeAsync() before calling getProfile(). INIT_SDK has not completed."
4218
3893
  );
4219
3894
  }
4220
3895
  if (!profile.id || !profile.username) {
4221
3896
  throw new Error(
4222
- "[Venus SDK] INIT_SDK returned an incomplete profile (missing id/username). The host must supply real credentials before rooms APIs are used."
3897
+ "[Venus SDK] INIT_SDK returned an incomplete profile (missing id/username). The host must supply valid profile data."
4223
3898
  );
4224
3899
  }
4225
3900
  return {
@@ -4233,6 +3908,10 @@ var HostProfileApi = class {
4233
3908
 
4234
3909
  // src/profile/MockProfileApi.ts
4235
3910
  var MockProfileApi = class {
3911
+ constructor(venusApi) {
3912
+ __publicField(this, "venusApi");
3913
+ this.venusApi = venusApi;
3914
+ }
4236
3915
  getCurrentProfile() {
4237
3916
  return {
4238
3917
  id: "mock_profile_123",
@@ -4245,69 +3924,282 @@ var MockProfileApi = class {
4245
3924
 
4246
3925
  // src/profile/index.ts
4247
3926
  function initializeProfile(venusApi, host) {
3927
+ venusApi.getProfile = () => {
3928
+ return host.profile.getCurrentProfile();
3929
+ };
4248
3930
  venusApi.getCurrentProfile = () => {
3931
+ console.warn(
3932
+ "[Venus SDK] DEPRECATED: VenusAPI.getCurrentProfile() is deprecated. Use VenusAPI.getProfile() instead. See migration guide: https://docs.venus.com/migration/profile-api"
3933
+ );
4249
3934
  return host.profile.getCurrentProfile();
4250
3935
  };
4251
3936
  }
4252
3937
 
4253
- // src/cdn/HostCdnApi.ts
4254
- var HostCdnApi = class {
4255
- constructor(baseUrl) {
4256
- __publicField(this, "baseUrl");
4257
- this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
3938
+ // src/system/HostSystemApi.ts
3939
+ var HostSystemApi = class {
3940
+ constructor(deviceApi, environmentApi, venusApi) {
3941
+ __publicField(this, "deviceApi");
3942
+ __publicField(this, "environmentApi");
3943
+ __publicField(this, "venusApi");
3944
+ this.deviceApi = deviceApi;
3945
+ this.environmentApi = environmentApi;
3946
+ this.venusApi = venusApi;
4258
3947
  }
4259
- async fetchBlob(path, options) {
4260
- const controller = new AbortController();
4261
- const timeoutId = setTimeout(
4262
- () => controller.abort(),
4263
- options?.timeout ?? 3e4
4264
- );
4265
- try {
4266
- const url = this.resolveAssetUrl(path);
4267
- const response = await fetch(url, {
4268
- mode: "cors",
4269
- credentials: "omit",
4270
- headers: { Accept: "/*" },
4271
- signal: controller.signal
4272
- });
4273
- clearTimeout(timeoutId);
4274
- if (!response.ok) {
4275
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
4276
- }
4277
- return await response.blob();
4278
- } catch (error) {
4279
- clearTimeout(timeoutId);
4280
- throw error;
4281
- }
3948
+ getDevice() {
3949
+ return this.deviceApi.getDevice();
4282
3950
  }
4283
- async fetchFromCdn(url, request) {
4284
- const response = await fetch(url, {
4285
- method: "GET",
4286
- headers: {
4287
- Accept: "application/json, text/plain, */*",
4288
- "Content-Type": "application/json"
4289
- },
4290
- mode: "cors",
4291
- cache: "no-cache"
4292
- });
4293
- if (!response.ok) {
3951
+ getEnvironment() {
3952
+ return this.environmentApi.getEnvironment();
3953
+ }
3954
+ getSafeArea() {
3955
+ const safeArea = this.venusApi._safeAreaData;
3956
+ if (!safeArea) {
4294
3957
  throw new Error(
4295
- `CDN fetch failed: \${response.status} \${response.statusText}`
3958
+ "[Venus SDK] getSafeArea() called before initialization. Call VenusAPI.initializeAsync() first."
4296
3959
  );
4297
3960
  }
4298
- return response;
3961
+ return { ...safeArea };
4299
3962
  }
4300
- getAssetCdnBaseUrl() {
4301
- return this.baseUrl;
3963
+ isMobile() {
3964
+ const environment = this.environmentApi.getEnvironment();
3965
+ if (environment.platform === "ios" || environment.platform === "android") {
3966
+ return true;
3967
+ }
3968
+ if (environment.browserInfo) {
3969
+ return environment.browserInfo.isMobile;
3970
+ }
3971
+ return true;
4302
3972
  }
4303
- resolveAssetUrl(subPath) {
4304
- const cleanSubPath = subPath.startsWith("/") ? subPath.slice(1) : subPath;
4305
- const pathParts = cleanSubPath.split("/");
4306
- const encodedParts = pathParts.map((part, index) => {
4307
- return index === pathParts.length - 1 ? encodeURIComponent(part) : part;
4308
- });
4309
- const encodedSubPath = encodedParts.join("/");
4310
- const fullUrl = this.baseUrl + "/" + encodedSubPath;
3973
+ isWeb() {
3974
+ const environment = this.environmentApi.getEnvironment();
3975
+ if (environment.platform === "web") {
3976
+ return true;
3977
+ }
3978
+ if (environment.browserInfo && !environment.browserInfo.isMobile) {
3979
+ return true;
3980
+ }
3981
+ return false;
3982
+ }
3983
+ };
3984
+
3985
+ // src/system/MockSystemApi.ts
3986
+ var MockSystemApi = class {
3987
+ constructor(deviceApi, environmentApi, venusApi) {
3988
+ __publicField(this, "deviceApi");
3989
+ __publicField(this, "environmentApi");
3990
+ __publicField(this, "venusApi");
3991
+ this.deviceApi = deviceApi;
3992
+ this.environmentApi = environmentApi;
3993
+ this.venusApi = venusApi;
3994
+ }
3995
+ getDevice() {
3996
+ return this.deviceApi.getDevice();
3997
+ }
3998
+ getEnvironment() {
3999
+ return this.environmentApi.getEnvironment();
4000
+ }
4001
+ getSafeArea() {
4002
+ const safeArea = this.venusApi._safeAreaData;
4003
+ if (!safeArea) {
4004
+ return {
4005
+ top: 0,
4006
+ right: 0,
4007
+ bottom: 34,
4008
+ left: 0
4009
+ };
4010
+ }
4011
+ return { ...safeArea };
4012
+ }
4013
+ isMobile() {
4014
+ const environment = this.environmentApi.getEnvironment();
4015
+ if (environment.platform === "ios" || environment.platform === "android") {
4016
+ return true;
4017
+ }
4018
+ if (environment.browserInfo) {
4019
+ return environment.browserInfo.isMobile;
4020
+ }
4021
+ return true;
4022
+ }
4023
+ isWeb() {
4024
+ const environment = this.environmentApi.getEnvironment();
4025
+ if (environment.platform === "web") {
4026
+ return true;
4027
+ }
4028
+ if (environment.browserInfo && !environment.browserInfo.isMobile) {
4029
+ return true;
4030
+ }
4031
+ return false;
4032
+ }
4033
+ };
4034
+
4035
+ // src/system/index.ts
4036
+ function initializeSystem(venusApi, host) {
4037
+ venusApi.system = host.system;
4038
+ venusApi.isMobile = () => {
4039
+ console.warn(
4040
+ "[Venus SDK] DEPRECATED: VenusAPI.isMobile() is deprecated. Use VenusAPI.system.isMobile() instead."
4041
+ );
4042
+ return host.system.isMobile();
4043
+ };
4044
+ venusApi.isWeb = () => {
4045
+ console.warn(
4046
+ "[Venus SDK] DEPRECATED: VenusAPI.isWeb() is deprecated. Use VenusAPI.system.isWeb() instead."
4047
+ );
4048
+ return host.system.isWeb();
4049
+ };
4050
+ }
4051
+
4052
+ // src/device/HostDeviceApi.ts
4053
+ var HostDeviceApi = class {
4054
+ constructor(venusApi) {
4055
+ __publicField(this, "venusApi");
4056
+ this.venusApi = venusApi;
4057
+ }
4058
+ getDevice() {
4059
+ const device = this.venusApi._deviceData;
4060
+ if (!device) {
4061
+ throw new Error(
4062
+ "[Venus SDK] Device info not available. You must await VenusAPI.initializeAsync() before calling getDevice(). INIT_SDK has not completed."
4063
+ );
4064
+ }
4065
+ return device;
4066
+ }
4067
+ };
4068
+
4069
+ // src/device/MockDeviceApi.ts
4070
+ var MockDeviceApi = class {
4071
+ constructor(venusApi) {
4072
+ __publicField(this, "venusApi");
4073
+ this.venusApi = venusApi;
4074
+ }
4075
+ getDevice() {
4076
+ const width = typeof window !== "undefined" ? window.innerWidth : 400;
4077
+ const height = typeof window !== "undefined" ? window.innerHeight : 800;
4078
+ return {
4079
+ screenSize: { width, height },
4080
+ viewportSize: {
4081
+ width: width - 20,
4082
+ // account for safe area
4083
+ height: height - 20
4084
+ },
4085
+ orientation: width > height ? "landscape" : "portrait",
4086
+ pixelRatio: typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1,
4087
+ fontScale: 1,
4088
+ deviceType: width > 768 ? "tablet" : "phone",
4089
+ hapticsEnabled: false,
4090
+ haptics: { supported: false, enabled: false }
4091
+ };
4092
+ }
4093
+ };
4094
+
4095
+ // src/environment/HostEnvironmentApi.ts
4096
+ var HostEnvironmentApi = class {
4097
+ constructor(venusApi) {
4098
+ __publicField(this, "venusApi");
4099
+ this.venusApi = venusApi;
4100
+ }
4101
+ getEnvironment() {
4102
+ const environment = this.venusApi._environmentData;
4103
+ if (!environment) {
4104
+ throw new Error(
4105
+ "[Venus SDK] Environment info not available. You must await VenusAPI.initializeAsync() before calling getEnvironment(). INIT_SDK has not completed."
4106
+ );
4107
+ }
4108
+ return environment;
4109
+ }
4110
+ };
4111
+
4112
+ // src/environment/MockEnvironmentApi.ts
4113
+ var MockEnvironmentApi = class {
4114
+ constructor(venusApi) {
4115
+ __publicField(this, "venusApi");
4116
+ this.venusApi = venusApi;
4117
+ }
4118
+ getEnvironment() {
4119
+ const getBrowser = () => {
4120
+ if (typeof navigator === "undefined") return "unknown";
4121
+ const userAgent = navigator.userAgent;
4122
+ if (/chrome|chromium|crios/i.test(userAgent)) return "chrome";
4123
+ if (/firefox|fxios/i.test(userAgent)) return "firefox";
4124
+ if (/safari/i.test(userAgent)) return "safari";
4125
+ if (/edg/i.test(userAgent)) return "edge";
4126
+ if (/opera|opr/i.test(userAgent)) return "opera";
4127
+ return "unknown";
4128
+ };
4129
+ return {
4130
+ isDevelopment: true,
4131
+ platform: "web",
4132
+ platformVersion: "mock-1.0",
4133
+ browserInfo: {
4134
+ browser: getBrowser(),
4135
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "mock-agent",
4136
+ isMobile: typeof navigator !== "undefined" ? /Mobi|Android/i.test(navigator.userAgent) : false,
4137
+ isTablet: typeof navigator !== "undefined" ? /iPad|Tablet|Pad/i.test(navigator.userAgent) : false,
4138
+ language: typeof navigator !== "undefined" ? navigator.language || "en-US" : "en-US"
4139
+ }
4140
+ };
4141
+ }
4142
+ };
4143
+
4144
+ // src/cdn/HostCdnApi.ts
4145
+ var HostCdnApi = class {
4146
+ constructor(baseUrl) {
4147
+ __publicField(this, "baseUrl");
4148
+ this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
4149
+ }
4150
+ async fetchBlob(path, options) {
4151
+ const controller = new AbortController();
4152
+ const timeoutId = setTimeout(
4153
+ () => controller.abort(),
4154
+ options?.timeout ?? 3e4
4155
+ );
4156
+ try {
4157
+ const url = this.resolveAssetUrl(path);
4158
+ const response = await fetch(url, {
4159
+ mode: "cors",
4160
+ credentials: "omit",
4161
+ headers: { Accept: "/*" },
4162
+ signal: controller.signal
4163
+ });
4164
+ clearTimeout(timeoutId);
4165
+ if (!response.ok) {
4166
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
4167
+ }
4168
+ return await response.blob();
4169
+ } catch (error) {
4170
+ clearTimeout(timeoutId);
4171
+ throw error;
4172
+ }
4173
+ }
4174
+ async fetchFromCdn(url, request) {
4175
+ const response = await fetch(url, {
4176
+ method: "GET",
4177
+ headers: {
4178
+ Accept: "application/json, text/plain, */*",
4179
+ "Content-Type": "application/json"
4180
+ },
4181
+ mode: "cors",
4182
+ cache: "no-cache"
4183
+ });
4184
+ if (!response.ok) {
4185
+ throw new Error(
4186
+ `CDN fetch failed: \${response.status} \${response.statusText}`
4187
+ );
4188
+ }
4189
+ return response;
4190
+ }
4191
+ getAssetCdnBaseUrl() {
4192
+ return this.baseUrl;
4193
+ }
4194
+ resolveAssetUrl(subPath) {
4195
+ const cleanSubPath = subPath.startsWith("/") ? subPath.slice(1) : subPath;
4196
+ const pathParts = cleanSubPath.split("/");
4197
+ const encodedParts = pathParts.map((part, index) => {
4198
+ return index === pathParts.length - 1 ? encodeURIComponent(part) : part;
4199
+ });
4200
+ const encodedSubPath = encodedParts.join("/");
4201
+ const cacheBust = Date.now();
4202
+ const fullUrl = this.baseUrl + "/" + encodedSubPath + `?cacheBust=${cacheBust}`;
4311
4203
  return fullUrl;
4312
4204
  }
4313
4205
  resolveAvatarAssetUrl(subPath) {
@@ -4322,9 +4214,15 @@ var HostCdnApi = class {
4322
4214
 
4323
4215
  // src/cdn/MockCdnApi.ts
4324
4216
  var MockCdnApi = class {
4325
- constructor() {
4326
- __publicField(this, "baseUrl");
4327
- this.baseUrl = "https://venus-static-01293ak.web.app/";
4217
+ constructor(venusApi) {
4218
+ __publicField(this, "venusApi");
4219
+ this.venusApi = venusApi;
4220
+ }
4221
+ get baseUrl() {
4222
+ return this.venusApi._mock?.cdnBaseUrl ?? "https://venus-static-01293ak.web.app/";
4223
+ }
4224
+ get forceRemoteCdn() {
4225
+ return this.venusApi._mock?.cdnForceRemote ?? false;
4328
4226
  }
4329
4227
  async fetchBlob(path, options) {
4330
4228
  const controller = new AbortController();
@@ -4361,6 +4259,10 @@ var MockCdnApi = class {
4361
4259
  return subPath;
4362
4260
  }
4363
4261
  const cleanSubPath = subPath.startsWith("/") ? subPath.slice(1) : subPath;
4262
+ const isLocalhost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
4263
+ if (isLocalhost && !this.forceRemoteCdn) {
4264
+ return `/${cleanSubPath}`;
4265
+ }
4364
4266
  const pathParts = cleanSubPath.split("/");
4365
4267
  const encodedParts = pathParts.map((part, index) => {
4366
4268
  return index === pathParts.length - 1 ? encodeURIComponent(part) : part;
@@ -4482,96 +4384,6 @@ function initializeCdn(venusApi, host) {
4482
4384
  venusApi.cdn = host.cdn;
4483
4385
  }
4484
4386
 
4485
- // src/post/MockPostApi.ts
4486
- init_core();
4487
- var MockPostApi = class {
4488
- constructor(venusApi) {
4489
- __publicField(this, "venusApi");
4490
- this.venusApi = venusApi;
4491
- }
4492
- async getPostInfo() {
4493
- const venusApi = this.venusApi;
4494
- await createMockDelay(MOCK_DELAYS.short);
4495
- return venusApi._mock.currentPostInteractions;
4496
- }
4497
- async openCommentsAsync() {
4498
- await createMockDelay(MOCK_DELAYS.short);
4499
- return {
4500
- opened: true,
4501
- commentsCount: 0
4502
- };
4503
- }
4504
- async toggleFollowAsync() {
4505
- const venusApi = this.venusApi;
4506
- console.log("[Venus Mock] *Toggling follow status");
4507
- await createMockDelay(MOCK_DELAYS.short);
4508
- venusApi._mock.currentPostInteractions.isFollowing = !venusApi._mock.currentPostInteractions.isFollowing;
4509
- const isFollowing = venusApi._mock.currentPostInteractions.isFollowing;
4510
- return {
4511
- isFollowing,
4512
- action: isFollowing ? "followed" : "unfollowed"
4513
- };
4514
- }
4515
- async toggleLikeAsync() {
4516
- const venusApi = this.venusApi;
4517
- await createMockDelay(MOCK_DELAYS.short);
4518
- venusApi._mock.currentPostInteractions.isLiked = !venusApi._mock.currentPostInteractions.isLiked;
4519
- const isLiked = venusApi._mock.currentPostInteractions.isLiked;
4520
- if (isLiked) {
4521
- venusApi._mock.currentPostInteractions.likesCount++;
4522
- } else {
4523
- venusApi._mock.currentPostInteractions.likesCount = Math.max(
4524
- 0,
4525
- venusApi._mock.currentPostInteractions.likesCount - 1
4526
- );
4527
- }
4528
- return {
4529
- isLiked,
4530
- likesCount: venusApi._mock.currentPostInteractions.likesCount,
4531
- action: isLiked ? "liked" : "unliked"
4532
- };
4533
- }
4534
- };
4535
-
4536
- // src/post/RpcPostApi.ts
4537
- var RpcPostApi = class {
4538
- constructor(rpcClient) {
4539
- __publicField(this, "rpcClient");
4540
- this.rpcClient = rpcClient;
4541
- }
4542
- getPostInfo() {
4543
- return this.rpcClient.call("H5_GET_POST_INTERACTIONS" /* GET_POST_INTERACTIONS */, {});
4544
- }
4545
- openCommentsAsync() {
4546
- return this.rpcClient.call("H5_OPEN_COMMENTS" /* OPEN_COMMENTS */, {});
4547
- }
4548
- toggleFollowAsync() {
4549
- return this.rpcClient.call(
4550
- "H5_TOGGLE_FOLLOW" /* TOGGLE_FOLLOW */,
4551
- {}
4552
- );
4553
- }
4554
- toggleLikeAsync() {
4555
- return this.rpcClient.call("H5_TOGGLE_LIKE" /* TOGGLE_LIKE */, {});
4556
- }
4557
- };
4558
-
4559
- // src/post/index.ts
4560
- function initializePost(venusApi, host) {
4561
- venusApi.getPostInteractionsAsync = () => {
4562
- return host.post.getPostInfo();
4563
- };
4564
- venusApi.toggleFollowAsync = () => {
4565
- return host.post.toggleFollowAsync();
4566
- };
4567
- venusApi.toggleLikeAsync = () => {
4568
- return host.post.toggleLikeAsync();
4569
- };
4570
- venusApi.openCommentsAsync = async () => {
4571
- await host.post.openCommentsAsync();
4572
- };
4573
- }
4574
-
4575
4387
  // src/haptics/RpcHapticsApi.ts
4576
4388
  var RpcHapticsApi = class {
4577
4389
  constructor(rpcClient) {
@@ -4762,871 +4574,426 @@ function initializeLifecycleApi(venusApi, host) {
4762
4574
  venusApi.lifecycles = host.lifecycle;
4763
4575
  }
4764
4576
 
4765
- // src/simulation/utils.ts
4766
- function sumContributions(contributions) {
4767
- const totals = {};
4768
- for (const profileId in contributions) {
4769
- for (const entityId in contributions[profileId]) {
4770
- const amount = contributions[profileId][entityId] || 0;
4771
- totals[entityId] = (totals[entityId] || 0) + amount;
4772
- }
4577
+ // src/rooms/VenusRoom.ts
4578
+ var VenusRoom = class {
4579
+ constructor(roomData) {
4580
+ __publicField(this, "id");
4581
+ __publicField(this, "name");
4582
+ __publicField(this, "players");
4583
+ __publicField(this, "maxPlayers");
4584
+ __publicField(this, "gameType");
4585
+ __publicField(this, "appId");
4586
+ __publicField(this, "type");
4587
+ __publicField(this, "createdBy");
4588
+ __publicField(this, "createdAt");
4589
+ __publicField(this, "updatedAt");
4590
+ __publicField(this, "isPrivate");
4591
+ __publicField(this, "status");
4592
+ __publicField(this, "customMetadata");
4593
+ __publicField(this, "admins");
4594
+ __publicField(this, "roomCode");
4595
+ __publicField(this, "description");
4596
+ __publicField(this, "data");
4597
+ __publicField(this, "version");
4598
+ this.id = roomData.id;
4599
+ this.name = roomData.name;
4600
+ this.players = Array.isArray(roomData.currentPlayers) ? [...roomData.currentPlayers] : [];
4601
+ this.maxPlayers = roomData.maxPlayers;
4602
+ this.gameType = roomData.gameType;
4603
+ this.appId = roomData.appId;
4604
+ this.type = roomData.type;
4605
+ this.createdBy = roomData.createdBy;
4606
+ this.createdAt = roomData.createdAt;
4607
+ this.updatedAt = roomData.updatedAt;
4608
+ this.isPrivate = roomData.isPrivate;
4609
+ this.status = roomData.status;
4610
+ this.customMetadata = roomData.customMetadata || {};
4611
+ this.admins = Array.isArray(roomData.admins) ? [...roomData.admins] : [];
4612
+ this.roomCode = roomData.roomCode;
4613
+ this.description = roomData.description;
4614
+ this.data = roomData.data || {};
4615
+ this.version = roomData.version;
4773
4616
  }
4774
- return totals;
4617
+ };
4618
+
4619
+ // src/rooms/setupRoomNotifications.ts
4620
+ function invokeCallbacks(callbacks, event, context) {
4621
+ callbacks.forEach((callback) => {
4622
+ try {
4623
+ callback(event);
4624
+ } catch (error) {
4625
+ console.error(`[Venus SDK] Error in ${context} callback:`, error);
4626
+ throw error;
4627
+ }
4628
+ });
4629
+ }
4630
+ function setupRoomNotifications(transport, getSubscriptions) {
4631
+ return transport.onVenusMessage((message) => {
4632
+ const subscriptions = getSubscriptions();
4633
+ if (!subscriptions) {
4634
+ return;
4635
+ }
4636
+ if (message.type === "H5_ROOM_DATA_UPDATED") {
4637
+ const messageData = message.data;
4638
+ const { roomId, roomData } = messageData;
4639
+ if (!roomId) return;
4640
+ const callbacks = subscriptions.data[roomId] || [];
4641
+ const event = {
4642
+ type: "H5_ROOM_DATA_UPDATED",
4643
+ roomId,
4644
+ roomData,
4645
+ timestamp: messageData.timestamp
4646
+ };
4647
+ invokeCallbacks(callbacks, event, "room data");
4648
+ }
4649
+ if (message.type === "H5_ROOM_MESSAGE_RECEIVED" || message.type === "H5_ROOM_MESSAGE_UPDATED" || message.type === "H5_ROOM_MESSAGE_DELETED") {
4650
+ const messageData = message.data;
4651
+ const { roomId } = messageData;
4652
+ if (!roomId) return;
4653
+ const callbacks = subscriptions.messages[roomId] || [];
4654
+ const event = {
4655
+ type: message.type,
4656
+ roomId,
4657
+ message: messageData.message,
4658
+ timestamp: messageData.timestamp
4659
+ };
4660
+ invokeCallbacks(callbacks, event, "room message");
4661
+ }
4662
+ if (message.type === "app:h5:proposedMoveValidationUpdated") {
4663
+ const messageData = message.data;
4664
+ const { roomId } = messageData;
4665
+ if (!roomId) return;
4666
+ const callbacks = subscriptions.gameEvents[roomId] || [];
4667
+ const event = {
4668
+ type: "app:h5:proposedMoveValidationUpdated",
4669
+ roomId,
4670
+ proposedMoveData: messageData.proposedMoveData,
4671
+ proposedMoveId: messageData.proposedMoveId,
4672
+ changeType: messageData.changeType,
4673
+ timestamp: messageData.timestamp
4674
+ };
4675
+ invokeCallbacks(callbacks, event, "game event");
4676
+ }
4677
+ });
4775
4678
  }
4776
4679
 
4777
- // src/simulation/RpcSimulationApi.ts
4778
- var RpcSimulationApi = class {
4680
+ // src/rooms/RpcRoomsApi.ts
4681
+ var RpcRoomsApi = class {
4779
4682
  constructor(rpcClient) {
4780
4683
  __publicField(this, "rpcClient");
4781
- __publicField(this, "_simulationConfig", null);
4684
+ __publicField(this, "subscriptions");
4782
4685
  this.rpcClient = rpcClient;
4686
+ this.subscriptions = {
4687
+ data: {},
4688
+ messages: {},
4689
+ gameEvents: {}
4690
+ };
4783
4691
  }
4784
- async validateSlotAssignmentAsync(containerId, slotId, itemId) {
4785
- return this.rpcClient.call(
4786
- "H5_SIMULATION_VALIDATE_ASSIGNMENT" /* H5_SIMULATION_VALIDATE_ASSIGNMENT */,
4787
- {
4788
- containerId,
4789
- slotId,
4790
- itemId
4791
- }
4792
- );
4793
- }
4794
- sumContributions(contributions) {
4795
- return sumContributions(contributions);
4796
- }
4797
- executeBatchOperationsAsync(operations, validateOnly) {
4798
- return this.rpcClient.call("H5_SIMULATION_BATCH_OPERATIONS" /* H5_SIMULATION_BATCH_OPERATIONS */, {
4799
- operations,
4800
- validateOnly
4801
- });
4692
+ /**
4693
+ * Get the subscription state for external access (used by setupRoomNotifications)
4694
+ */
4695
+ getSubscriptions() {
4696
+ return this.subscriptions;
4802
4697
  }
4803
- async getAvailableItemsAsync(containerId, slotId) {
4698
+ /**
4699
+ * Set up room notification routing from the transport
4700
+ */
4701
+ setupNotifications(transport) {
4702
+ setupRoomNotifications(transport, () => this.getSubscriptions());
4703
+ }
4704
+ async createRoomAsync(options) {
4804
4705
  const response = await this.rpcClient.call(
4805
- "H5_SIMULATION_GET_AVAILABLE_ITEMS" /* H5_SIMULATION_GET_AVAILABLE_ITEMS */,
4706
+ "H5_ROOM_CREATE" /* H5_ROOM_CREATE */,
4806
4707
  {
4807
- containerId,
4808
- slotId
4708
+ options
4809
4709
  }
4810
4710
  );
4811
- return response.availableItems || [];
4711
+ if (response.success === false) {
4712
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to create room";
4713
+ throw new Error(errorMessage);
4714
+ }
4715
+ const room = new VenusRoom(response.roomData);
4716
+ return room;
4812
4717
  }
4813
- calculatePowerPreviewAsync(containerId, slotId, candidateItemId) {
4814
- return this.rpcClient.call(
4815
- "H5_SIMULATION_CALCULATE_POWER_PREVIEW" /* H5_SIMULATION_CALCULATE_POWER_PREVIEW */,
4718
+ async joinOrCreateRoomAsync(options) {
4719
+ const response = await this.rpcClient.call(
4720
+ "H5_ROOM_JOIN_OR_CREATE" /* H5_ROOM_JOIN_OR_CREATE */,
4816
4721
  {
4817
- containerId,
4818
- slotId,
4819
- candidateItemId
4722
+ options
4820
4723
  }
4821
4724
  );
4725
+ if (response.success === false) {
4726
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to join or create room";
4727
+ throw new Error(errorMessage);
4728
+ }
4729
+ const room = new VenusRoom(response.value.roomData);
4730
+ return {
4731
+ action: response.value.action,
4732
+ room,
4733
+ playersJoined: response.value.playersJoined
4734
+ };
4822
4735
  }
4823
- assignItemToSlotAsync(containerId, slotId, itemId) {
4824
- return this.rpcClient.call("H5_SIMULATION_ASSIGN_ITEM" /* H5_SIMULATION_ASSIGN_ITEM */, {
4825
- containerId,
4826
- slotId,
4827
- itemId
4828
- });
4829
- }
4830
- removeItemFromSlotAsync(containerId, slotId) {
4831
- return this.rpcClient.call("H5_SIMULATION_REMOVE_ITEM" /* H5_SIMULATION_REMOVE_ITEM */, {
4832
- containerId,
4833
- slotId
4834
- });
4835
- }
4836
- async getSlotContainersAsync() {
4837
- const response = await this.rpcClient.call(
4838
- "H5_SIMULATION_GET_CONTAINERS" /* H5_SIMULATION_GET_CONTAINERS */,
4839
- {}
4840
- );
4841
- return response.containers || [];
4842
- }
4843
- async getSlotAssignmentsAsync(containerId) {
4736
+ async joinRoomByCodeAsync(roomCode) {
4844
4737
  const response = await this.rpcClient.call(
4845
- "H5_SIMULATION_GET_ASSIGNMENTS" /* H5_SIMULATION_GET_ASSIGNMENTS */,
4738
+ "H5_ROOM_JOIN_BY_CODE" /* H5_ROOM_JOIN_BY_CODE */,
4846
4739
  {
4847
- containerId
4740
+ roomCode
4848
4741
  }
4849
4742
  );
4850
- return Array.isArray(response) ? response : response.assignments || [];
4743
+ if (response?.success === false) {
4744
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to join room by code";
4745
+ throw new Error(errorMessage);
4746
+ }
4747
+ const room = new VenusRoom(response.roomData);
4748
+ return room;
4851
4749
  }
4852
- async getStateAsync(roomId) {
4750
+ // Get user's rooms with optional filtering
4751
+ async getUserRoomsAsync(options = {}) {
4853
4752
  const response = await this.rpcClient.call(
4854
- "H5_SIMULATION_GET_STATE" /* H5_SIMULATION_GET_STATE */,
4753
+ "H5_ROOM_GET_USER_ROOMS" /* H5_ROOM_GET_USER_ROOMS */,
4855
4754
  {
4856
- roomId
4755
+ includeArchived: options.includeArchived ?? false
4857
4756
  }
4858
4757
  );
4859
- console.log("[Venus SDK] getStateAsync", response);
4860
- if (response.configuration) {
4861
- this._simulationConfig = response.configuration;
4862
- }
4863
- return response;
4864
- }
4865
- async getConfigAsync(roomId) {
4866
- if (this._simulationConfig) {
4867
- return this._simulationConfig;
4868
- }
4869
- const config = await this.rpcClient.call(
4870
- "H5_SIMULATION_GET_CONFIG" /* H5_SIMULATION_GET_CONFIG */,
4871
- {}
4872
- );
4873
- console.log("[Venus SDK] getConfigAsync", config);
4874
- if (config) {
4875
- this._simulationConfig = config;
4876
- return config;
4758
+ if (response?.success === false) {
4759
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to get user rooms";
4760
+ throw new Error(errorMessage);
4877
4761
  }
4878
- throw new Error("No simulation configuration available");
4879
- }
4880
- executeRecipeAsync(recipeId, inputs, options) {
4881
- return this.rpcClient.call("H5_SIMULATION_EXECUTE_RECIPE" /* H5_SIMULATION_EXECUTE_RECIPE */, {
4882
- recipeId,
4883
- inputs,
4884
- roomId: options?.roomId,
4885
- batchAmount: options?.batchAmount,
4886
- allowPartialBatch: options?.allowPartialBatch,
4887
- entity: options?.entity
4888
- });
4889
- }
4890
- collectRecipeAsync(runId) {
4891
- return this.rpcClient.call("H5_SIMULATION_COLLECT_RECIPE" /* H5_SIMULATION_COLLECT_RECIPE */, {
4892
- runId
4893
- });
4894
- }
4895
- getActiveRunsAsync(options) {
4896
- return this.rpcClient.call("H5_SIMULATION_GET_ACTIVE_RUNS" /* H5_SIMULATION_GET_ACTIVE_RUNS */, {
4897
- roomId: options?.roomId
4898
- });
4899
- }
4900
- executeScopedRecipeAsync(recipeId, entity, inputs, options) {
4901
- return this.rpcClient.call(
4902
- "H5_SIMULATION_EXECUTE_SCOPED_RECIPE" /* H5_SIMULATION_EXECUTE_SCOPED_RECIPE */,
4903
- {
4904
- recipeId,
4905
- entity,
4906
- inputs,
4907
- roomId: options?.roomId ?? null,
4908
- options
4762
+ const venusRooms = [];
4763
+ for (const roomData of response.rooms) {
4764
+ if (!roomData.id) {
4765
+ console.warn("[Venus SDK] getUserRooms: Skipping room with missing ID:", roomData);
4766
+ continue;
4909
4767
  }
4910
- );
4768
+ try {
4769
+ const venusRoom = new VenusRoom(roomData);
4770
+ venusRooms.push(venusRoom);
4771
+ } catch (error) {
4772
+ console.warn(
4773
+ "[Venus SDK] getUserRooms: Failed to create VenusRoom object:",
4774
+ error,
4775
+ roomData
4776
+ );
4777
+ }
4778
+ }
4779
+ return venusRooms;
4911
4780
  }
4912
- getAvailableRecipesAsync(options) {
4913
- return this.rpcClient.call(
4914
- "H5_SIMULATION_GET_AVAILABLE_RECIPES" /* H5_SIMULATION_GET_AVAILABLE_RECIPES */,
4781
+ async updateRoomDataAsync(room, updates, options = {}) {
4782
+ const response = await this.rpcClient.call(
4783
+ "H5_ROOM_UPDATE_DATA" /* H5_ROOM_UPDATE_DATA */,
4915
4784
  {
4916
- roomId: options?.roomId || null,
4917
- includeActorRecipes: options?.includeActorRecipes || false
4785
+ roomId: room.id,
4786
+ updates,
4787
+ merge: options.merge ?? true
4918
4788
  }
4919
4789
  );
4790
+ if (response?.success === false) {
4791
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to update room data";
4792
+ throw new Error(errorMessage);
4793
+ }
4920
4794
  }
4921
- getRecipeRequirementsAsync(recipe) {
4922
- return this.rpcClient.call(
4923
- "H5_SIMULATION_GET_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_RECIPE_REQUIREMENTS */,
4795
+ async getRoomDataAsync(room) {
4796
+ const response = await this.rpcClient.call(
4797
+ "H5_ROOM_GET_DATA" /* H5_ROOM_GET_DATA */,
4924
4798
  {
4925
- recipeId: recipe.recipeId,
4926
- entity: recipe.entity,
4927
- batchAmount: recipe.batchAmount
4799
+ roomId: room.id
4928
4800
  }
4929
4801
  );
4802
+ if (response?.success === false) {
4803
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to get room data";
4804
+ throw new Error(errorMessage);
4805
+ }
4806
+ return response.data;
4930
4807
  }
4931
- getBatchRecipeRequirementsAsync(recipes) {
4932
- return this.rpcClient.call(
4933
- "H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS */,
4808
+ async sendRoomMessageAsync(venusRoom, request) {
4809
+ const response = await this.rpcClient.call(
4810
+ "H5_ROOM_SEND_MESSAGE" /* H5_ROOM_SEND_MESSAGE */,
4934
4811
  {
4935
- recipes
4812
+ roomId: venusRoom.id,
4813
+ message: request.message,
4814
+ metadata: request.metadata
4936
4815
  }
4937
4816
  );
4817
+ if (response?.success === false) {
4818
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to send message";
4819
+ throw new Error(errorMessage);
4820
+ }
4821
+ return response.messageId;
4938
4822
  }
4939
- triggerRecipeChainAsync(recipeId, options) {
4940
- return this.rpcClient.call(
4941
- "H5_SIMULATION_TRIGGER_RECIPE_CHAIN" /* H5_SIMULATION_TRIGGER_RECIPE_CHAIN */,
4823
+ async leaveRoomAsync(room) {
4824
+ const response = await this.rpcClient.call(
4825
+ "H5_ROOM_LEAVE" /* H5_ROOM_LEAVE */,
4942
4826
  {
4943
- triggerRecipeId: recipeId,
4944
- context: options?.context,
4945
- roomId: options?.roomId
4827
+ roomId: room.id
4946
4828
  }
4947
4829
  );
4830
+ if (response?.success === false) {
4831
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to leave room";
4832
+ throw new Error(errorMessage);
4833
+ }
4948
4834
  }
4949
- getEntityMetadataAsync(entityId) {
4950
- return this.rpcClient.call(
4951
- "H5_SIMULATION_GET_ENTITY_METADATA" /* H5_SIMULATION_GET_ENTITY_METADATA */,
4835
+ async startRoomGameAsync(room, options = {}) {
4836
+ const response = await this.rpcClient.call(
4837
+ "H5_ROOM_START_GAME" /* H5_ROOM_START_GAME */,
4952
4838
  {
4953
- entityId
4839
+ roomId: room.id,
4840
+ gameConfig: options.gameConfig ?? {},
4841
+ turnOrder: options.turnOrder ?? null
4954
4842
  }
4955
4843
  );
4844
+ if (response?.success === false) {
4845
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to start game";
4846
+ throw new Error(errorMessage);
4847
+ }
4956
4848
  }
4957
- async resolveFieldValueAsync(entityId, fieldPath, entity) {
4849
+ async proposeMoveAsync(room, proposalPayload) {
4958
4850
  const response = await this.rpcClient.call(
4959
- "H5_SIMULATION_RESOLVE_VALUE" /* H5_SIMULATION_RESOLVE_VALUE */,
4851
+ "h5:room:proposeMove" /* H5_ROOM_PROPOSE_MOVE */,
4960
4852
  {
4961
- entityId,
4962
- fieldPath,
4963
- entity
4853
+ roomId: room.id,
4854
+ gameSpecificState: proposalPayload.gameSpecificState,
4855
+ moveType: proposalPayload.moveType,
4856
+ clientContext: proposalPayload.clientContext,
4857
+ clientProposalId: proposalPayload.clientProposalId
4964
4858
  }
4965
4859
  );
4966
- return response.value;
4967
- }
4968
- };
4969
-
4970
- // src/simulation/MockSimulationApi.ts
4971
- function generateAppIdentifier2() {
4972
- if (typeof window === "undefined") return "unknown-app";
4973
- const url = window.location.href;
4974
- const match = url.match(/\/H5\/([^\/]+)/);
4975
- return match ? match[1] : "unknown-app";
4976
- }
4977
- var MockSimulationApi = class {
4978
- constructor(simulationConfig = null) {
4979
- __publicField(this, "mockSimulationConfigs", /* @__PURE__ */ new Map());
4980
- // appIdentifier -> config
4981
- __publicField(this, "mockSimulationStates", /* @__PURE__ */ new Map());
4982
- // appIdentifier -> config
4983
- __publicField(this, "mockActiveTimers", /* @__PURE__ */ new Map());
4984
- // appIdentifier -> timers[]
4985
- __publicField(this, "appId");
4986
- __publicField(this, "providedSimulationConfig");
4987
- this.appId = generateAppIdentifier2();
4988
- this.providedSimulationConfig = simulationConfig;
4989
- }
4990
- sumContributions(contributions) {
4991
- return sumContributions(contributions);
4992
- }
4993
- async validateSlotAssignmentAsync(containerId, slotId, itemId) {
4994
- this.log("validateSlotAssignmentAsync called:", {
4995
- containerId,
4996
- slotId,
4997
- itemId
4998
- });
4999
- return { valid: true, message: "Mock validation successful" };
5000
- }
5001
- async executeBatchOperationsAsync(operations, validateOnly) {
5002
- this.log("executeBatchOperationsAsync called:", {
5003
- operations,
5004
- validateOnly
5005
- });
5006
- return {
5007
- success: true,
5008
- results: operations.map(() => ({ success: true }))
5009
- };
5010
- }
5011
- async getAvailableItemsAsync(containerId, slotId) {
5012
- console.log("[Venus Simulation Mock] getAvailableItemsAsync called:", {
5013
- containerId,
5014
- slotId
5015
- });
5016
- const appIdentifier = generateAppIdentifier2();
5017
- const mockSimulationConfigs = this.mockSimulationConfigs;
5018
- const config = mockSimulationConfigs.get(appIdentifier) || {
5019
- entities: {}
5020
- };
5021
- const availableItems = Object.entries(config.entities).slice(0, 3).map(([entityId, entity]) => ({
5022
- entityId,
5023
- quantity: 1,
5024
- metadata: entity.metadata,
5025
- powerPreview: 100
5026
- // Mock power value
5027
- }));
5028
- return availableItems;
5029
- }
5030
- async calculatePowerPreviewAsync(containerId, slotId, candidateItemId) {
5031
- this.log("calculatePowerPreviewAsync called:", {
5032
- containerId,
5033
- slotId,
5034
- candidateItemId
5035
- });
5036
- return {
5037
- currentPower: 1e3,
5038
- previewPower: 1200,
5039
- powerDelta: 200,
5040
- breakdown: { base: 800, weapon: 200, armor: 200 }
5041
- };
5042
- }
5043
- async getSlotContainersAsync() {
5044
- this.log("getSlotContainersAsync called");
5045
- const appIdentifier = this.appId;
5046
- const mockSimulationConfigs = this.mockSimulationConfigs;
5047
- const config = mockSimulationConfigs.get(appIdentifier) || {
5048
- entities: {}
5049
- };
5050
- const containers = Object.entries(config.entities).filter(([_2, entity]) => entity.metadata?.slots).map(([entityId, entity]) => ({
5051
- entityId,
5052
- slots: entity.metadata?.slots,
5053
- isOwned: true
5054
- // Mock: assume all containers are owned
5055
- }));
5056
- return containers;
5057
- }
5058
- async getSlotAssignmentsAsync(containerId) {
5059
- this.log("getSlotAssignmentsAsync called for:", containerId);
5060
- return [];
5061
- }
5062
- async resolveFieldValueAsync(entityId, fieldPath, entity) {
5063
- this.log("resolveFieldValueAsync called:", {
5064
- entityId,
5065
- fieldPath,
5066
- entity
5067
- });
5068
- const mockValues = {
5069
- basePower: 850,
5070
- weaponPower: 300,
5071
- armorPower: 150,
5072
- total_power: 1300,
5073
- total_defense_power: 5e3
5074
- };
5075
- return mockValues[fieldPath] || 100;
5076
- }
5077
- async getEntityMetadataAsync(entityId) {
5078
- this.log("getEntityMetadataAsync called for:", entityId);
5079
- const mockSimulationConfigs = this.mockSimulationConfigs;
5080
- const appIdentifier = this.appId;
5081
- const config = mockSimulationConfigs.get(
5082
- appIdentifier
5083
- ) || {
5084
- entities: {}};
5085
- const entity = config.entities[entityId];
5086
- return entity?.metadata || {};
5087
- }
5088
- async collectRecipeAsync(runId) {
5089
- this.log("collectRecipeAsync called:", { runId });
5090
- const mockRewards = {
5091
- cash: Math.floor(Math.random() * 1e3) + 500,
5092
- experience: Math.floor(Math.random() * 50) + 25
5093
- };
5094
- return {
5095
- success: true,
5096
- runId,
5097
- rewards: mockRewards,
5098
- message: "Rewards collected successfully"
5099
- };
5100
- }
5101
- executeRecipeAsync(recipeId, inputs, options) {
5102
- this.log("executeRecipeAsync called:", {
5103
- recipeId,
5104
- inputs,
5105
- options
5106
- });
5107
- const appIdentifier = this.appId;
5108
- return this.executeRecipe(appIdentifier, recipeId, inputs);
5109
- }
5110
- async executeScopedRecipeAsync(recipeId, entity, inputs, options) {
5111
- this.log("executeScopedRecipeAsync called:", {
5112
- recipeId,
5113
- entity,
5114
- inputs,
5115
- roomId: options?.roomId,
5116
- options
5117
- });
5118
- return {
5119
- success: true,
5120
- message: "Mock scoped recipe execution successful"
5121
- };
5122
- }
5123
- async getActiveRunsAsync(options) {
5124
- this.log("getActiveRunsAsync called:", options);
5125
- const appIdentifier = this.appId;
5126
- let state = this.mockSimulationStates.get(appIdentifier);
5127
- if (!state) {
5128
- state = await this.initializeSimulationState(appIdentifier);
5129
- }
5130
- return state.activeRuns || [];
5131
- }
5132
- async getAvailableRecipesAsync(options) {
5133
- this.log("getAvailableRecipesAsync called:", options);
5134
- const baseRecipes = [
5135
- { id: "collect_resources", scope: "player", clientViewable: true },
5136
- { id: "upgrade_equipment", scope: "player", clientViewable: true }
5137
- ];
5138
- if (options?.roomId) {
5139
- baseRecipes.push(
5140
- { id: "room_upgrade", scope: "room", clientViewable: true },
5141
- { id: "cooperative_project", scope: "room", clientViewable: true }
5142
- );
5143
- }
5144
- if (options?.includeActorRecipes && options?.roomId) {
5145
- baseRecipes.push(
5146
- { id: "trade_with_npc", scope: "actor", clientViewable: true },
5147
- { id: "attack_monster", scope: "actor", clientViewable: true }
5148
- );
4860
+ if (response?.success === false) {
4861
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to propose move";
4862
+ throw new Error(errorMessage);
5149
4863
  }
5150
- return { success: true, recipes: baseRecipes };
5151
- }
5152
- async getBatchRecipeRequirementsAsync(recipes) {
5153
- this.log("getBatchRecipeRequirementsAsync called:", {
5154
- count: recipes?.length
5155
- });
5156
- const results = (recipes || []).map((q) => ({
5157
- recipeId: q.recipeId,
5158
- entity: q.entity || null,
5159
- amount: q.batchAmount || 1,
5160
- inputs: { cash: "BE:0" },
5161
- canAfford: true,
5162
- disabled: false
5163
- }));
5164
- return { success: true, results };
5165
- }
5166
- async getRecipeRequirementsAsync(recipe) {
5167
- this.log("getRecipeRequirementsAsync called:", recipe);
5168
- return {
5169
- recipeId: recipe.recipeId,
5170
- entity: recipe.entity || null,
5171
- amount: recipe.batchAmount,
5172
- inputs: { cash: "BE:0" },
5173
- canAfford: true,
5174
- disabled: false
5175
- };
4864
+ return response.data;
5176
4865
  }
5177
- async triggerRecipeChainAsync(recipeId, options) {
5178
- this.log("triggerRecipeChainAsync called:", { recipeId, ...options });
4866
+ async validateMoveAsync(_room, moveId, verdict) {
5179
4867
  return {
5180
4868
  success: true,
5181
- message: "Mock recipe chain triggered successfully"
4869
+ moveId,
4870
+ isValid: verdict.isValid,
4871
+ reason: verdict.reason
5182
4872
  };
5183
4873
  }
5184
- log(message, ...args) {
5185
- console.log(`[Venus Sim Mock] ${message}`, args);
5186
- }
5187
- async executeRecipe(appIdentifier, recipeId, inputs) {
5188
- this.log(`Executing recipe ${recipeId} for ${appIdentifier}`, inputs);
5189
- const mockSimulationConfigs = this.mockSimulationConfigs;
5190
- const mockSimulationStates = this.mockSimulationStates;
5191
- let config = mockSimulationConfigs.get(appIdentifier);
5192
- let state = mockSimulationStates.get(appIdentifier);
5193
- if (!config || !state) {
5194
- state = await this.initializeSimulationState(appIdentifier);
5195
- config = mockSimulationConfigs.get(appIdentifier);
5196
- if (!config) {
5197
- throw new Error("Failed to initialize simulation config");
5198
- }
5199
- }
5200
- const recipe = config.recipes?.[recipeId];
5201
- if (!recipe) {
5202
- throw new Error(`Recipe ${recipeId} not found`);
5203
- }
5204
- if (state.disabledRecipes?.includes(recipeId)) {
5205
- throw new Error(`Recipe ${recipeId} is disabled`);
5206
- }
5207
- if (recipe.inputs) {
5208
- for (const [entityId, required] of Object.entries(recipe.inputs)) {
5209
- const available = state.inventory[entityId] || 0;
5210
- if (available < required) {
5211
- throw new Error(
5212
- `Insufficient ${entityId}: required ${required}, available ${available}`
5213
- );
5214
- }
4874
+ async subscribeAsync(room, options = {}) {
4875
+ const roomId = room.id;
4876
+ const existingData = this.subscriptions.data[roomId];
4877
+ const existingMessages = this.subscriptions.messages[roomId];
4878
+ const existingGameEvents = this.subscriptions.gameEvents[roomId];
4879
+ const subscribeToData = Boolean(options.onData) && (existingData?.length ?? 0) === 0;
4880
+ const subscribeToMessages = Boolean(options.onMessages) && (existingMessages?.length ?? 0) === 0;
4881
+ const subscribeToProposedMoves = Boolean(options.onGameEvents) && (existingGameEvents?.length ?? 0) === 0;
4882
+ if (subscribeToData || subscribeToMessages || subscribeToProposedMoves) {
4883
+ try {
4884
+ await this.rpcClient.call("H5_ROOM_SUBSCRIBE" /* H5_ROOM_SUBSCRIBE */, {
4885
+ roomId,
4886
+ subscribeToData,
4887
+ subscribeToMessages,
4888
+ subscribeToProposedMoves
4889
+ });
4890
+ } catch (error) {
4891
+ console.error("[Venus SDK] Failed to set up room subscription:", error);
4892
+ throw error;
5215
4893
  }
5216
4894
  }
5217
- if (recipe.inputs) {
5218
- for (const [entityId, input] of Object.entries(recipe.inputs)) {
5219
- const inventoryValue = state.inventory[entityId] || 0;
5220
- if (typeof input === "number" && typeof inventoryValue === "number") {
5221
- state.inventory[entityId] = inventoryValue - input;
5222
- }
4895
+ if (options.onData) {
4896
+ if (!this.subscriptions.data[roomId]) {
4897
+ this.subscriptions.data[roomId] = [];
5223
4898
  }
4899
+ this.subscriptions.data[roomId].push(options.onData);
5224
4900
  }
5225
- if (recipe.beginEffects) {
5226
- this.applyEffects(state, recipe.beginEffects);
5227
- }
5228
- const runId = this.generateRunId();
5229
- const now = Date.now();
5230
- const expiresAt = now + (recipe.duration || 0);
5231
- const run = {
5232
- id: runId,
5233
- recipeId,
5234
- status: "running",
5235
- startTime: now,
5236
- expiresAt,
5237
- inputs: recipe.inputs || {}
5238
- };
5239
- state.activeRuns.push(run);
5240
- if (recipe.duration === 0) {
5241
- this.completeRun(appIdentifier, runId);
5242
- return { status: "completed", runId };
5243
- } else {
5244
- const mockActiveTimers = this.mockActiveTimers;
5245
- const timer = setTimeout(() => {
5246
- this.completeRun(appIdentifier, runId);
5247
- }, recipe.duration);
5248
- const timers = mockActiveTimers.get(appIdentifier) || [];
5249
- timers.push(timer);
5250
- mockActiveTimers.set(appIdentifier, timers);
5251
- return {
5252
- status: "running",
5253
- runId,
5254
- expiresAt: new Date(expiresAt).toISOString()
5255
- };
5256
- }
5257
- }
5258
- async initializeSimulationState(appIdentifier) {
5259
- this.log(`Initializing simulation state for ${appIdentifier}`);
5260
- const providedSimulationConfig = this.providedSimulationConfig;
5261
- const mockSimulationConfigs = this.mockSimulationConfigs;
5262
- const mockSimulationStates = this.mockSimulationStates;
5263
- const mockActiveTimers = this.mockActiveTimers;
5264
- const config = providedSimulationConfig || {
5265
- version: "1.0",
5266
- entities: {},
5267
- recipes: {}
5268
- };
5269
- mockSimulationConfigs.set(appIdentifier, config);
5270
- const initialInventory = {};
5271
- if (providedSimulationConfig && config.entities) {
5272
- Object.keys(config.entities).forEach((entityId) => {
5273
- initialInventory[entityId] = 0;
5274
- });
4901
+ if (options.onMessages) {
4902
+ if (!this.subscriptions.messages[roomId]) {
4903
+ this.subscriptions.messages[roomId] = [];
4904
+ }
4905
+ this.subscriptions.messages[roomId].push(options.onMessages);
5275
4906
  }
5276
- const state = {
5277
- inventory: initialInventory,
5278
- activeRuns: [],
5279
- disabledRecipes: new Array()
5280
- };
5281
- if (config.recipes) {
5282
- Object.entries(config.recipes).forEach(([recipeId, recipe]) => {
5283
- if (recipe.metadata?.startsDisabled) {
5284
- state.disabledRecipes.push(recipeId);
5285
- }
5286
- });
4907
+ if (options.onGameEvents) {
4908
+ if (!this.subscriptions.gameEvents[roomId]) {
4909
+ this.subscriptions.gameEvents[roomId] = [];
4910
+ }
4911
+ this.subscriptions.gameEvents[roomId].push(options.onGameEvents);
5287
4912
  }
5288
- mockSimulationStates.set(appIdentifier, state);
5289
- mockActiveTimers.set(appIdentifier, []);
5290
- console.log(
5291
- `[Venus Simulation Mock] Initialized state for ${appIdentifier}:`,
5292
- state
5293
- );
5294
- if (config.recipes) {
5295
- Object.entries(config.recipes).forEach(([recipeId, recipe]) => {
5296
- const isAutoRestart = recipe.autoRestart || recipe.metadata?.autoRestart;
5297
- if (isAutoRestart && recipe.outputs) {
5298
- this.log(`Found auto-restart recipe: ${recipeId}`, {
5299
- topLevelAutoRestart: recipe.autoRestart,
5300
- metadataAutoRestart: recipe.metadata?.autoRestart,
5301
- hasOutputs: !!recipe.outputs,
5302
- duration: recipe.duration
5303
- });
5304
- const condition = recipe.maxRestartCondition || recipe.metadata?.maxRestartCondition;
5305
- if (condition && condition.entity) {
5306
- const currentAmount = initialInventory[condition.entity] || 0;
5307
- if (currentAmount < condition.maxValue) {
5308
- console.log(
5309
- `[Venus Simulation Mock] Auto-starting ${recipeId} at initialization`,
5310
- {
5311
- currentAmount,
5312
- maxValue: condition.maxValue,
5313
- entity: condition.entity
5314
- }
5315
- );
5316
- setTimeout(() => {
5317
- this.executeRecipe(appIdentifier, recipeId, {});
5318
- }, 1e3);
5319
- }
5320
- } else {
5321
- console.log(
5322
- `[Venus Simulation Mock] Auto-starting ${recipeId} at initialization (no condition)`
5323
- );
5324
- setTimeout(() => {
5325
- this.executeRecipe(appIdentifier, recipeId, {});
5326
- }, 1e3);
4913
+ let disposed = false;
4914
+ return () => {
4915
+ if (disposed) return;
4916
+ disposed = true;
4917
+ if (options.onData) {
4918
+ const callbacks = this.subscriptions.data[roomId];
4919
+ if (callbacks) {
4920
+ const index = callbacks.indexOf(options.onData);
4921
+ if (index > -1) {
4922
+ callbacks.splice(index, 1);
5327
4923
  }
5328
4924
  }
5329
- });
5330
- }
5331
- return state;
5332
- }
5333
- generateRunId() {
5334
- return "run_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
5335
- }
5336
- completeRun(appIdentifier, runId) {
5337
- this.log(`Completing run ${runId} for ${appIdentifier}`);
5338
- const mockSimulationConfigs = this.mockSimulationConfigs;
5339
- const mockSimulationStates = this.mockSimulationStates;
5340
- const config = mockSimulationConfigs.get(appIdentifier);
5341
- const state = mockSimulationStates.get(appIdentifier);
5342
- if (!config || !state) return;
5343
- const runIndex = state.activeRuns.findIndex((r2) => r2.id === runId);
5344
- if (runIndex === -1) return;
5345
- const run = state.activeRuns[runIndex];
5346
- const recipe = config.recipes?.[run.recipeId];
5347
- if (!recipe) return;
5348
- const outputs = {};
5349
- const rng = this.createSeededRandom(runId);
5350
- if (recipe.outputs) {
5351
- for (const [entityId, value] of Object.entries(recipe.outputs)) {
5352
- if (typeof value === "number") {
5353
- outputs[entityId] = value;
5354
- } else if (typeof value === "object" && value != null && "min" in value && "max" in value && typeof value.min == "number" && typeof value.max === "number") {
5355
- outputs[entityId] = Math.floor(rng() * (value.max - value.min + 1)) + value.min;
5356
- }
5357
4925
  }
5358
- }
5359
- for (const [entityId, amount] of Object.entries(outputs)) {
5360
- state.inventory[entityId] = (state.inventory[entityId] || 0) + amount;
5361
- }
5362
- if (recipe.endEffects) {
5363
- this.applyEffects(state, recipe.endEffects);
5364
- }
5365
- run.status = "completed";
5366
- run.outputs = outputs;
5367
- state.activeRuns.splice(runIndex, 1);
5368
- const isAutoRestart = recipe.autoRestart || recipe.metadata?.autoRestart;
5369
- if (isAutoRestart) {
5370
- console.log(
5371
- `[Venus Simulation Mock] Checking auto-restart for ${run.recipeId}`,
5372
- {
5373
- topLevelAutoRestart: recipe.autoRestart,
5374
- metadataAutoRestart: recipe.metadata?.autoRestart,
5375
- hasCondition: !!(recipe.maxRestartCondition || recipe.metadata?.maxRestartCondition)
5376
- }
5377
- );
5378
- const condition = recipe.maxRestartCondition || recipe.metadata?.maxRestartCondition;
5379
- if (condition) {
5380
- const currentAmount = state.inventory[condition.entity] || 0;
5381
- if (currentAmount < condition.maxValue) {
5382
- console.log(
5383
- `[Venus Simulation Mock] Auto-restarting ${run.recipeId}`,
5384
- {
5385
- currentAmount,
5386
- maxValue: condition.maxValue,
5387
- entity: condition.entity
5388
- }
5389
- );
5390
- setTimeout(() => {
5391
- this.executeRecipe(appIdentifier, run.recipeId, recipe.inputs || {});
5392
- }, 1e3);
4926
+ if (options.onMessages) {
4927
+ const callbacks = this.subscriptions.messages[roomId];
4928
+ if (callbacks) {
4929
+ const index = callbacks.indexOf(options.onMessages);
4930
+ if (index > -1) {
4931
+ callbacks.splice(index, 1);
4932
+ }
5393
4933
  }
5394
- } else {
5395
- console.log(
5396
- `[Venus Simulation Mock] Auto-restarting ${run.recipeId} (no condition)`
5397
- );
5398
- setTimeout(() => {
5399
- this.executeRecipe(appIdentifier, run.recipeId, recipe.inputs || {});
5400
- }, 1e3);
5401
4934
  }
5402
- }
5403
- console.log(
5404
- `[Venus Simulation Mock] Completed run ${runId}, outputs:`,
5405
- outputs
5406
- );
5407
- }
5408
- createSeededRandom(seed) {
5409
- let hash = 0;
5410
- for (let i = 0; i < seed.length; i++) {
5411
- const char = seed.charCodeAt(i);
5412
- hash = (hash << 5) - hash + char;
5413
- hash = hash & hash;
5414
- }
5415
- return () => {
5416
- hash = (hash * 9301 + 49297) % 233280;
5417
- return hash / 233280;
5418
- };
5419
- }
5420
- applyEffects(state, effects) {
5421
- if (!effects || !Array.isArray(effects)) return;
5422
- for (const effect of effects) {
5423
- switch (effect.type) {
5424
- case "set":
5425
- state.inventory[effect.target] = effect.value;
5426
- console.log(
5427
- `[Venus Simulation Mock] Effect: Set ${effect.target} = ${effect.value}`
5428
- );
5429
- break;
5430
- case "add":
5431
- state.inventory[effect.target] = (state.inventory[effect.target] || 0) + effect.value;
5432
- console.log(
5433
- `[Venus Simulation Mock] Effect: Add ${effect.value} to ${effect.target} (new value: ${state.inventory[effect.target]})`
5434
- );
5435
- break;
5436
- case "multiply":
5437
- state.inventory[effect.target] = (state.inventory[effect.target] || 0) * effect.value;
5438
- console.log(
5439
- `[Venus Simulation Mock] Effect: Multiply ${effect.target} by ${effect.value} (new value: ${state.inventory[effect.target]})`
5440
- );
5441
- break;
5442
- case "min":
5443
- state.inventory[effect.target] = Math.max(
5444
- state.inventory[effect.target] || 0,
5445
- effect.value
5446
- );
5447
- console.log(
5448
- `[Venus Simulation Mock] Effect: Set ${effect.target} min ${effect.value} (new value: ${state.inventory[effect.target]})`
5449
- );
5450
- break;
5451
- case "max":
5452
- state.inventory[effect.target] = Math.min(
5453
- state.inventory[effect.target] || 0,
5454
- effect.value
5455
- );
5456
- console.log(
5457
- `[Venus Simulation Mock] Effect: Set ${effect.target} max ${effect.value} (new value: ${state.inventory[effect.target]})`
5458
- );
5459
- break;
5460
- case "enable_recipe":
5461
- if (state.disabledRecipes?.includes(effect.target)) {
5462
- state.disabledRecipes = state.disabledRecipes.filter(
5463
- (r2) => r2 !== effect.target
5464
- );
5465
- console.log(
5466
- `[Venus Simulation Mock] Effect: Enabled recipe ${effect.target}`
5467
- );
4935
+ if (options.onGameEvents) {
4936
+ const callbacks = this.subscriptions.gameEvents[roomId];
4937
+ if (callbacks) {
4938
+ const index = callbacks.indexOf(options.onGameEvents);
4939
+ if (index > -1) {
4940
+ callbacks.splice(index, 1);
5468
4941
  }
5469
- break;
5470
- case "disable_recipe":
5471
- if (!state.disabledRecipes) state.disabledRecipes = [];
5472
- if (!state.disabledRecipes.includes(effect.target)) {
5473
- state.disabledRecipes.push(effect.target);
5474
- console.log(
5475
- `[Venus Simulation Mock] Effect: Disabled recipe ${effect.target}`
5476
- );
5477
- }
5478
- break;
5479
- case "trigger_recipe":
5480
- console.log(
5481
- `[Venus Simulation Mock] Effect: Trigger recipe ${effect.target} (not implemented)`
5482
- );
5483
- break;
5484
- default:
5485
- console.warn(
5486
- `[Venus Simulation Mock] Unknown effect type: ${effect.type}`
5487
- );
4942
+ }
4943
+ }
4944
+ const hasAnySubscriptions = (this.subscriptions.data[roomId]?.length ?? 0) > 0 || (this.subscriptions.messages[roomId]?.length ?? 0) > 0 || (this.subscriptions.gameEvents[roomId]?.length ?? 0) > 0;
4945
+ if (!hasAnySubscriptions) {
4946
+ this.rpcClient.call("H5_ROOM_UNSUBSCRIBE" /* H5_ROOM_UNSUBSCRIBE */, {
4947
+ roomId
4948
+ }).catch((error) => {
4949
+ console.error("[Venus SDK] Failed to clean up room subscription:", error);
4950
+ });
5488
4951
  }
5489
- }
5490
- }
5491
- async getConfigAsync() {
5492
- console.log("[Venus Simulation Mock] getConfigAsync called");
5493
- const appIdentifier = this.appId;
5494
- const mockSimulationConfigs = this.mockSimulationConfigs;
5495
- const config = mockSimulationConfigs.get(appIdentifier) || {
5496
- version: "1.0",
5497
- entities: {},
5498
- recipes: {}
5499
- };
5500
- return config;
5501
- }
5502
- async getStateAsync(roomId) {
5503
- this.log("getStateAsync called:", roomId);
5504
- const appIdentifier = this.appId;
5505
- const mockSimulationStates = this.mockSimulationStates;
5506
- let state = mockSimulationStates.get(appIdentifier);
5507
- if (!state) {
5508
- state = await this.initializeSimulationState(appIdentifier);
5509
- }
5510
- const mockSimulationConfigs = this.mockSimulationConfigs;
5511
- return {
5512
- ...state,
5513
- roomId,
5514
- configuration: mockSimulationConfigs.get(appIdentifier)
5515
4952
  };
5516
4953
  }
5517
- async assignItemToSlotAsync(containerId, slotId, itemId) {
5518
- this.log("assignItemToSlotAsync called:", {
5519
- containerId,
5520
- slotId,
5521
- itemId
5522
- });
5523
- return { success: true, message: "Mock assignment successful" };
5524
- }
5525
- async removeItemFromSlotAsync(containerId, slotId) {
5526
- this.log("removeItemFromSlotAsync called:", {
5527
- containerId,
5528
- slotId
5529
- });
5530
- return { success: true, message: "Mock removal successful" };
5531
- }
5532
4954
  };
5533
4955
 
5534
- // src/simulation/index.ts
5535
- function initializeSimulation(venusApi, host) {
5536
- console.log("[Venus SDK] Initializing new Simulation Api");
5537
- venusApi.simulation = {
5538
- isEnabled: () => true
5539
- };
5540
- venusApi.simulation.getConfigAsync = () => {
5541
- return host.simulation.getConfigAsync();
5542
- };
5543
- venusApi.simulation.getStateAsync = (options) => {
5544
- return host.simulation.getStateAsync(options?.roomId);
5545
- };
5546
- venusApi.simulation.executeRecipeAsync = (recipeId, inputs, options) => {
5547
- return host.simulation.executeRecipeAsync(recipeId, inputs, options);
5548
- };
5549
- venusApi.simulation.getActiveRunsAsync = () => {
5550
- return host.simulation.getActiveRunsAsync();
5551
- };
5552
- venusApi.simulation.collectRecipeAsync = (runId) => {
5553
- return host.simulation.collectRecipeAsync(runId);
5554
- };
5555
- venusApi.simulation.executeScopedRecipeAsync = (recipeId, entity, inputs, roomId, options) => {
5556
- return host.simulation.executeScopedRecipeAsync(recipeId, entity, inputs, {
5557
- roomId,
5558
- ...options
5559
- });
5560
- };
5561
- venusApi.simulation.triggerRecipeChainAsync = (recipeId, context, roomId) => {
5562
- return host.simulation.triggerRecipeChainAsync(recipeId, {
5563
- context,
5564
- roomId
5565
- });
5566
- };
5567
- venusApi.simulation.getAvailableRecipesAsync = async (roomId, includeActorRecipes) => {
5568
- const result = await host.simulation.getAvailableRecipesAsync({
5569
- roomId,
5570
- includeActorRecipes
5571
- });
5572
- return result.recipes;
5573
- };
5574
- venusApi.simulation.getRecipeRequirementsAsync = (recipeId, entity, amount) => {
5575
- return host.simulation.getRecipeRequirementsAsync({
5576
- recipeId,
5577
- entity,
5578
- batchAmount: amount
5579
- });
5580
- };
5581
- venusApi.simulation.getBatchRecipeRequirementsAsync = (recipes) => {
5582
- return host.simulation.getBatchRecipeRequirementsAsync(recipes);
5583
- };
5584
- venusApi.simulation.resolveFieldValueAsync = (entityId, fieldPath, entity) => {
5585
- return host.simulation.resolveFieldValueAsync(entityId, fieldPath, entity);
5586
- };
5587
- venusApi.simulation.getEntityMetadataAsync = (entityId) => {
5588
- return host.simulation.getEntityMetadataAsync(entityId);
5589
- };
5590
- venusApi.simulation.getSlotAssignmentsAsync = (containerId) => {
5591
- return host.simulation.getSlotAssignmentsAsync(containerId);
5592
- };
5593
- venusApi.simulation.getSlotContainersAsync = () => {
5594
- return host.simulation.getSlotContainersAsync();
5595
- };
5596
- venusApi.simulation.assignItemToSlotAsync = (containerId, slotId, itemId) => {
5597
- return host.simulation.assignItemToSlotAsync(containerId, slotId, itemId);
5598
- };
5599
- venusApi.simulation.removeItemFromSlotAsync = (containerId, slotId) => {
5600
- return host.simulation.removeItemFromSlotAsync(containerId, slotId);
5601
- };
5602
- venusApi.simulation.getAvailableItemsAsync = (containerId, slotId) => {
5603
- return host.simulation.getAvailableItemsAsync(containerId, slotId);
5604
- };
5605
- venusApi.simulation.calculatePowerPreviewAsync = (containerId, slotId, candidateItemId) => {
5606
- return host.simulation.calculatePowerPreviewAsync(
5607
- containerId,
5608
- slotId,
5609
- candidateItemId
5610
- );
5611
- };
5612
- venusApi.simulation.executeBatchOperationsAsync = (operations, validateOnly) => {
5613
- return host.simulation.executeBatchOperationsAsync(operations, validateOnly);
5614
- };
5615
- venusApi.simulation.validateSlotAssignmentAsync = (containerId, slotId, itemId) => {
5616
- return host.simulation.validateSlotAssignmentAsync(
5617
- containerId,
5618
- slotId,
5619
- itemId
4956
+ // src/rooms/index.ts
4957
+ function bindMethod(target, targetKey, source, sourceKey) {
4958
+ const key = sourceKey ?? targetKey;
4959
+ const fn = source?.[key];
4960
+ if (typeof fn === "function") {
4961
+ target[targetKey] = fn.bind(source);
4962
+ return true;
4963
+ }
4964
+ return false;
4965
+ }
4966
+ function initializeRoomsApi(venusApi, host) {
4967
+ const roomsApi = host?.rooms;
4968
+ if (!roomsApi) {
4969
+ console.warn(
4970
+ "[Venus SDK] Host did not provide a rooms implementation. Rooms API will be unavailable."
5620
4971
  );
5621
- };
5622
- venusApi.simulation.sumContributions = (contributions) => {
5623
- return host.simulation.sumContributions(contributions);
5624
- };
4972
+ return;
4973
+ }
4974
+ const venus = venusApi;
4975
+ const existingNamespace = venus.rooms || {};
4976
+ const roomsNamespace = Object.assign({}, existingNamespace);
4977
+ const namespaceBindings = [
4978
+ ["createRoomAsync"],
4979
+ ["joinOrCreateRoomAsync"],
4980
+ ["joinRoomByCodeAsync"],
4981
+ ["getUserRoomsAsync"],
4982
+ ["subscribeAsync"],
4983
+ ["updateRoomDataAsync"],
4984
+ ["getRoomDataAsync"],
4985
+ ["sendRoomMessageAsync"],
4986
+ ["leaveRoomAsync"],
4987
+ ["startRoomGameAsync"],
4988
+ ["proposeMoveAsync"],
4989
+ ["validateMoveAsync"]
4990
+ ];
4991
+ namespaceBindings.forEach(([targetKey, sourceKey]) => {
4992
+ bindMethod(roomsNamespace, targetKey, roomsApi, sourceKey);
4993
+ });
4994
+ venus.rooms = roomsNamespace;
5625
4995
  }
5626
4996
 
5627
- // src/MockHost.ts
5628
- init_rooms();
5629
-
5630
4997
  // src/logging/MockLoggingApi.ts
5631
4998
  var MockLoggingApi = class {
5632
4999
  logDebug(message, ...args) {
@@ -5702,9 +5069,173 @@ function initializeLoggingApi(venusApi, host) {
5702
5069
  };
5703
5070
  }
5704
5071
 
5705
- // src/shared-assets/consts.ts
5706
- var BurgerTimeAssetsCdnPath = "burger-time/Core.stow";
5707
- var CharacterAssetsCdnPath = "burger-time/Character.stow";
5072
+ // src/shared-assets/embeddedLibrariesManifest.ts
5073
+ var EMBEDDED_LIBRARIES = [
5074
+ {
5075
+ libraryKey: "phaser@3.90.0",
5076
+ assetKey: "library:phaser@3.90.0",
5077
+ packageName: "phaser",
5078
+ version: "3.90.0",
5079
+ globalVar: "Phaser",
5080
+ cdnPath: "phaser/3.90.0/phaser.min.js",
5081
+ moduleSpecifiers: [{ match: "exact", value: "phaser" }],
5082
+ loadStage: 0,
5083
+ enabled: true
5084
+ },
5085
+ {
5086
+ libraryKey: "react@18.3.1",
5087
+ assetKey: "library:react@18.3.1",
5088
+ packageName: "react",
5089
+ version: "18.3.1",
5090
+ globalVar: "React",
5091
+ cdnPath: "react/18.3.1/react.production.min.js",
5092
+ moduleSpecifiers: [
5093
+ { match: "exact", value: "react", behavior: "namespace" },
5094
+ { match: "exact", value: "react/jsx-runtime", behavior: "react-jsx-runtime" },
5095
+ {
5096
+ match: "exact",
5097
+ value: "react/jsx-dev-runtime",
5098
+ behavior: "react-jsx-dev-runtime"
5099
+ }
5100
+ ],
5101
+ loadStage: 0,
5102
+ // Must load before ReactDOM
5103
+ enabled: true
5104
+ },
5105
+ {
5106
+ libraryKey: "react-dom@18.3.1",
5107
+ assetKey: "library:react-dom@18.3.1",
5108
+ packageName: "react-dom",
5109
+ version: "18.3.1",
5110
+ globalVar: "ReactDOM",
5111
+ cdnPath: "react-dom/18.3.1/react-dom.production.min.js",
5112
+ moduleSpecifiers: [
5113
+ { match: "exact", value: "react-dom", behavior: "namespace" },
5114
+ { match: "exact", value: "react-dom/client", behavior: "namespace" }
5115
+ ],
5116
+ loadStage: 1,
5117
+ // Depends on React (stage 0)
5118
+ enabled: true
5119
+ },
5120
+ {
5121
+ libraryKey: "three@0.170.0",
5122
+ assetKey: "library:three@0.170.0",
5123
+ packageName: "three",
5124
+ version: "0.170.0",
5125
+ globalVar: "THREE",
5126
+ cdnPath: "three/r170/three.min.js",
5127
+ moduleSpecifiers: [
5128
+ { match: "exact", value: "three", behavior: "namespace" },
5129
+ { match: "prefix", value: "three/examples/jsm/", behavior: "namespace" }
5130
+ ],
5131
+ loadStage: 0,
5132
+ enabled: true
5133
+ },
5134
+ {
5135
+ libraryKey: "matter-js@0.19.0",
5136
+ assetKey: "library:matter-js@0.19.0",
5137
+ packageName: "matter-js",
5138
+ version: "0.19.0",
5139
+ globalVar: "Matter",
5140
+ cdnPath: "matter-js/0.19.0/matter.min.js",
5141
+ moduleSpecifiers: [{ match: "exact", value: "matter-js" }],
5142
+ loadStage: 0,
5143
+ enabled: true
5144
+ },
5145
+ {
5146
+ libraryKey: "inkjs@2.2.0",
5147
+ assetKey: "library:inkjs@2.2.0",
5148
+ packageName: "inkjs",
5149
+ version: "2.2.0",
5150
+ globalVar: "inkjs",
5151
+ cdnPath: "inkjs/2.2.0/ink.min.js",
5152
+ moduleSpecifiers: [{ match: "exact", value: "inkjs" }],
5153
+ loadStage: 0,
5154
+ enabled: true
5155
+ },
5156
+ {
5157
+ libraryKey: "zustand@5.0.3",
5158
+ assetKey: "library:zustand@5.0.3",
5159
+ packageName: "zustand",
5160
+ version: "5.0.3",
5161
+ globalVar: "zustand",
5162
+ cdnPath: "zustand/5.0.3/zustand.min.js",
5163
+ moduleSpecifiers: [
5164
+ { match: "exact", value: "zustand" },
5165
+ { match: "exact", value: "zustand/middleware" }
5166
+ ],
5167
+ loadStage: 0,
5168
+ enabled: true
5169
+ },
5170
+ {
5171
+ libraryKey: "ammo.js@2024.11",
5172
+ assetKey: "library:ammo.js@2024.11",
5173
+ packageName: "ammo.js",
5174
+ version: "2024.11",
5175
+ globalVar: "Ammo",
5176
+ cdnPath: "ammo/2024.11/ammo.js",
5177
+ moduleSpecifiers: [
5178
+ { match: "exact", value: "ammo.js" },
5179
+ { match: "exact", value: "ammo.js/builds/ammo.wasm.js" }
5180
+ ],
5181
+ loadStage: 0,
5182
+ enabled: false
5183
+ // Not ready yet - WASM loading needs additional work
5184
+ }
5185
+ ];
5186
+ var EMBEDDED_LIBRARY_BY_KEY = EMBEDDED_LIBRARIES.reduce(
5187
+ (acc, lib) => {
5188
+ acc[lib.libraryKey] = lib;
5189
+ return acc;
5190
+ },
5191
+ {}
5192
+ );
5193
+ EMBEDDED_LIBRARIES.filter(
5194
+ (lib) => lib.enabled
5195
+ ).flatMap(
5196
+ (lib) => lib.moduleSpecifiers.map((specifier) => ({
5197
+ ...specifier,
5198
+ libraryKey: lib.libraryKey
5199
+ }))
5200
+ );
5201
+ function getLibraryDefinition(libraryKey) {
5202
+ const definition = EMBEDDED_LIBRARY_BY_KEY[libraryKey];
5203
+ if (!definition) {
5204
+ const availableKeys = Object.keys(EMBEDDED_LIBRARY_BY_KEY).join(", ");
5205
+ throw new Error(
5206
+ `Unsupported embedded library: ${libraryKey}. Available libraries: ${availableKeys}`
5207
+ );
5208
+ }
5209
+ return definition;
5210
+ }
5211
+
5212
+ // src/shared-assets/base64Utils.ts
5213
+ function base64ToArrayBuffer(base64) {
5214
+ const binaryString = atob(base64);
5215
+ const len = binaryString.length;
5216
+ const bytes = new Uint8Array(len);
5217
+ for (let i = 0; i < len; i++) {
5218
+ bytes[i] = binaryString.charCodeAt(i);
5219
+ }
5220
+ return bytes.buffer;
5221
+ }
5222
+ function base64ToUtf8(base64) {
5223
+ if (typeof TextDecoder !== "undefined") {
5224
+ const decoder = new TextDecoder("utf-8");
5225
+ const buffer = base64ToArrayBuffer(base64);
5226
+ return decoder.decode(new Uint8Array(buffer));
5227
+ }
5228
+ if (typeof globalThis !== "undefined" && typeof globalThis.Buffer !== "undefined") {
5229
+ const BufferCtor = globalThis.Buffer;
5230
+ return BufferCtor.from(base64, "base64").toString("utf-8");
5231
+ }
5232
+ const binaryString = atob(base64);
5233
+ let result = "";
5234
+ for (let i = 0; i < binaryString.length; i++) {
5235
+ result += String.fromCharCode(binaryString.charCodeAt(i));
5236
+ }
5237
+ return decodeURIComponent(escape(result));
5238
+ }
5708
5239
 
5709
5240
  // src/shared-assets/RpcSharedAssetsApi.ts
5710
5241
  var RpcSharedAssetsApi = class {
@@ -5714,46 +5245,48 @@ var RpcSharedAssetsApi = class {
5714
5245
  this.rpcClient = rpcClient;
5715
5246
  this.venusApi = venusApi;
5716
5247
  }
5717
- async loadBurgerTimeAssetsBundle() {
5248
+ async loadAssetsBundle(game, bundleKey, fileType = "stow") {
5718
5249
  try {
5719
5250
  const response = await this.rpcClient.callT("H5_LOAD_EMBEDDED_ASSET" /* H5_LOAD_EMBEDDED_ASSET */, {
5720
- assetKey: "burgerTimeCoreBundle"
5251
+ assetKey: bundleKey
5721
5252
  });
5722
5253
  return base64ToArrayBuffer(response.base64Data);
5723
5254
  } catch (err) {
5724
5255
  try {
5725
- const blob = await this.venusApi.cdn.fetchBlob(BurgerTimeAssetsCdnPath);
5256
+ const blob = await this.venusApi.cdn.fetchBlob(`${game}/${bundleKey}.${fileType}`);
5726
5257
  return await blob.arrayBuffer();
5727
5258
  } catch (e) {
5728
- throw new Error("Failed to load burgerTimeAssetsBundle");
5259
+ throw new Error(`Failed to load ${bundleKey}`);
5729
5260
  }
5730
5261
  }
5731
5262
  }
5732
- async loadCharactersBundle() {
5263
+ async loadLibraryCode(libraryKey) {
5264
+ const definition = getLibraryDefinition(libraryKey);
5733
5265
  try {
5734
5266
  const response = await this.rpcClient.callT("H5_LOAD_EMBEDDED_ASSET" /* H5_LOAD_EMBEDDED_ASSET */, {
5735
- assetKey: "characters"
5267
+ assetKey: definition.assetKey
5736
5268
  });
5737
- return base64ToArrayBuffer(response.base64Data);
5269
+ return base64ToUtf8(response.base64Data);
5738
5270
  } catch (err) {
5271
+ console.error(
5272
+ `[Venus Libraries] Failed to load ${libraryKey} from host via RPC:`,
5273
+ err
5274
+ );
5275
+ console.warn(
5276
+ `[Venus Libraries] Falling back to CDN for ${libraryKey}. This may indicate an asset packaging issue.`
5277
+ );
5739
5278
  try {
5740
- const blob = await this.venusApi.cdn.fetchBlob(CharacterAssetsCdnPath);
5741
- return await blob.arrayBuffer();
5742
- } catch (e) {
5743
- throw new Error("Failed to load charactersBundle");
5279
+ const cdnUrl = this.venusApi.cdn.resolveSharedLibUrl(definition.cdnPath);
5280
+ const response = await this.venusApi.cdn.fetchFromCdn(cdnUrl);
5281
+ return await response.text();
5282
+ } catch (cdnError) {
5283
+ throw new Error(
5284
+ `Failed to load embedded library ${libraryKey}: RPC failed, CDN fallback failed: ${cdnError.message}`
5285
+ );
5744
5286
  }
5745
5287
  }
5746
5288
  }
5747
5289
  };
5748
- function base64ToArrayBuffer(base64) {
5749
- const binaryString = atob(base64);
5750
- const len = binaryString.length;
5751
- const bytes = new Uint8Array(len);
5752
- for (let i = 0; i < len; i++) {
5753
- bytes[i] = binaryString.charCodeAt(i);
5754
- }
5755
- return bytes.buffer;
5756
- }
5757
5290
 
5758
5291
  // src/shared-assets/MockSharedAssetsApi.ts
5759
5292
  var MockSharedAssetsApi = class {
@@ -5761,13 +5294,15 @@ var MockSharedAssetsApi = class {
5761
5294
  __publicField(this, "venusApi");
5762
5295
  this.venusApi = venusApi;
5763
5296
  }
5764
- async loadBurgerTimeAssetsBundle() {
5765
- const blob = await this.venusApi.cdn.fetchBlob(BurgerTimeAssetsCdnPath);
5297
+ async loadAssetsBundle(game, bundleKey, fileType = "stow") {
5298
+ const blob = await this.venusApi.cdn.fetchBlob(`${game}/${bundleKey}.${fileType}`);
5766
5299
  return await blob.arrayBuffer();
5767
5300
  }
5768
- async loadCharactersBundle() {
5769
- const blob = await this.venusApi.cdn.fetchBlob(CharacterAssetsCdnPath);
5770
- return await blob.arrayBuffer();
5301
+ async loadLibraryCode(libraryKey) {
5302
+ const definition = getLibraryDefinition(libraryKey);
5303
+ const url = this.venusApi.cdn.resolveSharedLibUrl(definition.cdnPath);
5304
+ const response = await this.venusApi.cdn.fetchFromCdn(url);
5305
+ return await response.text();
5771
5306
  }
5772
5307
  };
5773
5308
 
@@ -5848,44 +5383,116 @@ var ROOMS_UNAVAILABLE_MESSAGE = "[Venus SDK] Rooms API is only available when ru
5848
5383
  function createUnavailableRoomsApi() {
5849
5384
  const roomsUnavailableError = () => new Error(ROOMS_UNAVAILABLE_MESSAGE);
5850
5385
  return {
5851
- async createRoom() {
5386
+ async createRoomAsync() {
5852
5387
  throw roomsUnavailableError();
5853
5388
  },
5854
- async joinOrCreateRoom() {
5389
+ async joinOrCreateRoomAsync() {
5855
5390
  throw roomsUnavailableError();
5856
5391
  },
5857
- async getUserRooms() {
5392
+ async joinRoomByCodeAsync() {
5858
5393
  throw roomsUnavailableError();
5859
5394
  },
5860
- async joinRoomByCode() {
5395
+ async getUserRoomsAsync() {
5861
5396
  throw roomsUnavailableError();
5862
5397
  },
5863
- subscribe() {
5398
+ async subscribeAsync() {
5864
5399
  throw roomsUnavailableError();
5865
5400
  },
5866
- async updateData() {
5401
+ async updateRoomDataAsync() {
5867
5402
  throw roomsUnavailableError();
5868
5403
  },
5869
- async getData() {
5404
+ async getRoomDataAsync() {
5870
5405
  throw roomsUnavailableError();
5871
5406
  },
5872
- async sendMessage() {
5407
+ async sendRoomMessageAsync() {
5873
5408
  throw roomsUnavailableError();
5874
5409
  },
5875
- async leave() {
5410
+ async leaveRoomAsync() {
5876
5411
  throw roomsUnavailableError();
5877
5412
  },
5878
- async startGame() {
5413
+ async startRoomGameAsync() {
5879
5414
  throw roomsUnavailableError();
5880
5415
  },
5881
- async proposeMove() {
5416
+ async proposeMoveAsync() {
5882
5417
  throw roomsUnavailableError();
5883
5418
  },
5884
- async validateMove() {
5419
+ async validateMoveAsync() {
5885
5420
  throw roomsUnavailableError();
5886
5421
  }
5887
5422
  };
5888
5423
  }
5424
+ var SIMULATION_UNAVAILABLE_MESSAGE = "[Venus SDK] Simulation API is only available when running inside the Venus host environment.";
5425
+ function createUnavailableSimulationApi() {
5426
+ const simulationUnavailableError = () => new Error(SIMULATION_UNAVAILABLE_MESSAGE);
5427
+ return {
5428
+ isEnabled() {
5429
+ return false;
5430
+ },
5431
+ async getStateAsync() {
5432
+ throw simulationUnavailableError();
5433
+ },
5434
+ async getConfigAsync() {
5435
+ throw simulationUnavailableError();
5436
+ },
5437
+ async executeRecipeAsync() {
5438
+ throw simulationUnavailableError();
5439
+ },
5440
+ async getActiveRunsAsync() {
5441
+ throw simulationUnavailableError();
5442
+ },
5443
+ async collectRecipeAsync() {
5444
+ throw simulationUnavailableError();
5445
+ },
5446
+ async executeScopedRecipeAsync() {
5447
+ throw simulationUnavailableError();
5448
+ },
5449
+ async triggerRecipeChainAsync() {
5450
+ throw simulationUnavailableError();
5451
+ },
5452
+ async getAvailableRecipesAsync() {
5453
+ throw simulationUnavailableError();
5454
+ },
5455
+ async getRecipeRequirementsAsync() {
5456
+ throw simulationUnavailableError();
5457
+ },
5458
+ async getBatchRecipeRequirementsAsync() {
5459
+ throw simulationUnavailableError();
5460
+ },
5461
+ async resolveFieldValueAsync() {
5462
+ throw simulationUnavailableError();
5463
+ },
5464
+ async getEntityMetadataAsync() {
5465
+ throw simulationUnavailableError();
5466
+ },
5467
+ async getSlotContainersAsync() {
5468
+ throw simulationUnavailableError();
5469
+ },
5470
+ async getSlotAssignmentsAsync() {
5471
+ throw simulationUnavailableError();
5472
+ },
5473
+ async assignItemToSlotAsync() {
5474
+ throw simulationUnavailableError();
5475
+ },
5476
+ async removeItemFromSlotAsync() {
5477
+ throw simulationUnavailableError();
5478
+ },
5479
+ async getAvailableItemsAsync() {
5480
+ throw simulationUnavailableError();
5481
+ },
5482
+ async calculatePowerPreviewAsync() {
5483
+ throw simulationUnavailableError();
5484
+ },
5485
+ async validateSlotAssignmentAsync() {
5486
+ throw simulationUnavailableError();
5487
+ },
5488
+ async executeBatchOperationsAsync() {
5489
+ throw simulationUnavailableError();
5490
+ },
5491
+ async subscribeAsync() {
5492
+ throw simulationUnavailableError();
5493
+ }
5494
+ };
5495
+ }
5889
5496
  var MockHost = class {
5890
5497
  constructor(venusApi) {
5891
5498
  __publicField(this, "ads");
@@ -5898,9 +5505,9 @@ var MockHost = class {
5898
5505
  __publicField(this, "notifications");
5899
5506
  __publicField(this, "popups");
5900
5507
  __publicField(this, "profile");
5508
+ __publicField(this, "system");
5901
5509
  __publicField(this, "cdn");
5902
5510
  __publicField(this, "time");
5903
- __publicField(this, "post");
5904
5511
  __publicField(this, "ai");
5905
5512
  __publicField(this, "haptics");
5906
5513
  __publicField(this, "features");
@@ -5932,15 +5539,17 @@ var MockHost = class {
5932
5539
  this.navigation = new MockNavigationApi(venusApi);
5933
5540
  this.notifications = new MockNotificationsApi(venusApi);
5934
5541
  this.popups = new MockPopupsApi(this._overlay);
5935
- this.profile = new MockProfileApi();
5936
- this.cdn = new MockCdnApi();
5542
+ this.profile = new MockProfileApi(venusApi);
5543
+ const deviceApi = new MockDeviceApi(venusApi);
5544
+ const environmentApi = new MockEnvironmentApi(venusApi);
5545
+ this.system = new MockSystemApi(deviceApi, environmentApi, venusApi);
5546
+ this.cdn = new MockCdnApi(venusApi);
5937
5547
  this.time = new MockTimeApi(venusApi);
5938
- this.post = new MockPostApi(venusApi);
5939
5548
  this.ai = new MockAiApi();
5940
5549
  this.haptics = new MockHapticsApi(venusApi);
5941
5550
  this.features = new MockFeaturesApi();
5942
5551
  this.lifecycle = this._mockLifecyclesApi;
5943
- this.simulation = new MockSimulationApi();
5552
+ this.simulation = createUnavailableSimulationApi();
5944
5553
  this.rooms = createUnavailableRoomsApi();
5945
5554
  this.logging = new MockLoggingApi();
5946
5555
  this.iap = new MockIapApi();
@@ -5956,40 +5565,17 @@ var MockHost = class {
5956
5565
  }
5957
5566
  initialize(options) {
5958
5567
  this._isInitialized = true;
5959
- const controls = this.updateUiControls();
5568
+ this.venusApi._profileData = this.profile.getCurrentProfile();
5569
+ this.venusApi._deviceData = this.system.getDevice();
5570
+ this.venusApi._environmentData = this.system.getEnvironment();
5571
+ this.venusApi._localeData = this.venusApi._mock?.locale || "en-US";
5572
+ this.venusApi._languageCodeData = this.venusApi._mock?.languageCode || "en";
5960
5573
  return Promise.resolve({
5961
5574
  initializeAsleep: false,
5962
- hudInsets: {
5963
- top: controls.feedHeader.height,
5964
- bottom: 0,
5965
- left: 0,
5966
- right: 0
5967
- }
5575
+ safeArea: this.venusApi._safeAreaData
5968
5576
  });
5969
5577
  }
5970
- updateUiControls() {
5971
- const controls = {
5972
- closeButton: { x: 16, y: 16, width: 32, height: 32 },
5973
- menuButton: {
5974
- x: window.innerWidth - 48,
5975
- y: 16,
5976
- width: 32,
5977
- height: 32
5978
- },
5979
- feedHeader: { x: 0, y: 0, width: window.innerWidth, height: 56 },
5980
- playButton: {
5981
- x: 0,
5982
- y: window.innerHeight - 60,
5983
- width: window.innerWidth,
5984
- height: 60
5985
- }
5986
- };
5987
- return controls;
5988
- }
5989
5578
  createOverlay() {
5990
- const venusApi = this.venusApi;
5991
- venusApi.config.ui.controls = this.updateUiControls();
5992
- const uiControls = venusApi.config.ui.controls;
5993
5579
  const overlayContainer = document.createElement("div");
5994
5580
  overlayContainer.id = "venus-mock-overlay";
5995
5581
  overlayContainer.style.cssText = `
@@ -6005,7 +5591,7 @@ var MockHost = class {
6005
5591
  const menuButton = this.createOverlayButton(
6006
5592
  "close",
6007
5593
  "Menu",
6008
- uiControls.menuButton,
5594
+ { x: window.innerWidth - 48, y: 16, width: 32, height: 32 },
6009
5595
  () => {
6010
5596
  this.handleMenuButtonClicked();
6011
5597
  },
@@ -6234,17 +5820,13 @@ var MockHost = class {
6234
5820
  return button;
6235
5821
  }
6236
5822
  updateOverlayLayout() {
6237
- const venusApi = this.venusApi;
6238
5823
  const overlay = this._overlay;
6239
- venusApi.config.ui.controls = this.updateUiControls();
6240
- const uiControls = venusApi.config.ui.controls;
6241
5824
  const menuBtn = overlay.elements.menuButton;
6242
- const menuPos = uiControls.menuButton;
6243
- menuBtn.style.left = `${menuPos.x}px`;
6244
- menuBtn.style.top = `${menuPos.y}px`;
6245
- menuBtn.style.width = `${menuPos.width}px`;
6246
- menuBtn.style.minWidth = `${menuPos.width}px`;
6247
- menuBtn.style.height = `${menuPos.height}px`;
5825
+ menuBtn.style.left = `${window.innerWidth - 48}px`;
5826
+ menuBtn.style.top = "16px";
5827
+ menuBtn.style.width = "32px";
5828
+ menuBtn.style.minWidth = "32px";
5829
+ menuBtn.style.height = "32px";
6248
5830
  }
6249
5831
  triggerLifecycleEvent(name) {
6250
5832
  console.log("Trigger Lifecycle Event: ", name);
@@ -6432,6 +6014,11 @@ var MockHost = class {
6432
6014
  }
6433
6015
  };
6434
6016
 
6017
+ // src/utils/idGenerator.ts
6018
+ function generateId() {
6019
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
6020
+ }
6021
+
6435
6022
  // src/rpc/RpcClient.ts
6436
6023
  var RpcClient = class {
6437
6024
  constructor() {
@@ -6474,7 +6061,7 @@ var RpcClient = class {
6474
6061
  }
6475
6062
  async call(method, args, timeout = 5e3) {
6476
6063
  return new Promise((resolve, reject) => {
6477
- const id = this.generateId();
6064
+ const id = generateId();
6478
6065
  this.addPendingCall(id, resolve, reject);
6479
6066
  const request = {
6480
6067
  type: "rpc-request",
@@ -6511,9 +6098,6 @@ var RpcClient = class {
6511
6098
  getPendingCall(id) {
6512
6099
  return this.pendingCalls.get(id);
6513
6100
  }
6514
- generateId() {
6515
- return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
6516
- }
6517
6101
  handleRpcResponse(response) {
6518
6102
  const pending = this.getPendingCall(response.id);
6519
6103
  if (!pending) {
@@ -6576,6 +6160,16 @@ var VenusTransport = class {
6576
6160
  this.isProcessingMessage = false;
6577
6161
  return;
6578
6162
  }
6163
+ if (message.type === "H5_SIMULATION_UPDATE" /* H5_SIMULATION_UPDATE */) {
6164
+ const notification = {
6165
+ type: "rpc-notification",
6166
+ id: message.type,
6167
+ payload: message.data
6168
+ };
6169
+ this.handleNotification(notification);
6170
+ this.isProcessingMessage = false;
6171
+ return;
6172
+ }
6579
6173
  const requestId = messageData.requestId;
6580
6174
  if (!requestId) {
6581
6175
  this.logWarn("No requestId. Ignoring message...");
@@ -6742,294 +6336,361 @@ var VenusTransport = class {
6742
6336
  }
6743
6337
  };
6744
6338
 
6745
- // src/RemoteHost.ts
6746
- init_rooms();
6747
-
6748
- // src/rooms/RpcRoomsApi.ts
6749
- init_VenusRoom();
6750
- var RpcRoomsApi = class {
6339
+ // src/simulation/RpcSimulationApi.ts
6340
+ var RpcSimulationApi = class {
6751
6341
  constructor(rpcClient) {
6752
6342
  __publicField(this, "rpcClient");
6753
- __publicField(this, "subscriptions");
6754
- __publicField(this, "transportSubscription", null);
6343
+ __publicField(this, "_simulationConfig", null);
6344
+ __publicField(this, "subscriptionCallbacks", /* @__PURE__ */ new Map());
6755
6345
  this.rpcClient = rpcClient;
6756
- this.subscriptions = {
6757
- data: {},
6758
- messages: {},
6759
- gameEvents: {},
6760
- allEvents: {}
6761
- };
6346
+ this.rpcClient.onNotification(
6347
+ "H5_SIMULATION_UPDATE" /* H5_SIMULATION_UPDATE */,
6348
+ this.handleSimulationUpdate.bind(this)
6349
+ );
6762
6350
  }
6763
- /**
6764
- * Get the subscription state for external access (used by setupRoomNotifications)
6765
- */
6766
- getSubscriptions() {
6767
- return this.subscriptions;
6351
+ isEnabled() {
6352
+ return true;
6768
6353
  }
6769
- /**
6770
- * Set up room notification routing from the transport
6771
- */
6772
- setupNotifications(transport) {
6773
- const { setupRoomNotifications: setupRoomNotifications2 } = (init_rooms(), __toCommonJS(rooms_exports));
6774
- this.transportSubscription = setupRoomNotifications2(
6775
- transport,
6776
- () => this.getSubscriptions()
6354
+ async validateSlotAssignmentAsync(containerId, slotId, itemId) {
6355
+ return this.rpcClient.call(
6356
+ "H5_SIMULATION_VALIDATE_ASSIGNMENT" /* H5_SIMULATION_VALIDATE_ASSIGNMENT */,
6357
+ {
6358
+ containerId,
6359
+ slotId,
6360
+ itemId
6361
+ }
6777
6362
  );
6778
6363
  }
6779
- /**
6780
- * Clean up subscriptions and resources
6781
- */
6782
- dispose() {
6783
- if (this.transportSubscription) {
6784
- this.transportSubscription.unsubscribe();
6785
- this.transportSubscription = null;
6786
- console.log("[Venus Rooms] Cleaned up room notification subscription");
6364
+ async subscribeAsync(options) {
6365
+ this.ensureValidSubscribeOptions(options);
6366
+ const subscriptionId = generateId();
6367
+ this.subscriptionCallbacks.set(subscriptionId, options.onUpdate);
6368
+ try {
6369
+ await this.rpcClient.call("H5_SIMULATION_SUBSCRIBE" /* H5_SIMULATION_SUBSCRIBE */, {
6370
+ subscriptionId,
6371
+ entities: options.entities,
6372
+ tags: options.tags,
6373
+ activeRuns: options.activeRuns,
6374
+ roomId: options.roomId
6375
+ });
6376
+ } catch (error) {
6377
+ this.subscriptionCallbacks.delete(subscriptionId);
6378
+ throw error;
6787
6379
  }
6380
+ let unsubscribed = false;
6381
+ return () => {
6382
+ if (unsubscribed) {
6383
+ return;
6384
+ }
6385
+ unsubscribed = true;
6386
+ this.subscriptionCallbacks.delete(subscriptionId);
6387
+ void this.rpcClient.call("H5_SIMULATION_UNSUBSCRIBE" /* H5_SIMULATION_UNSUBSCRIBE */, {
6388
+ subscriptionId
6389
+ }).catch((error) => {
6390
+ console.error(
6391
+ "[Venus SDK] Failed to unsubscribe simulation listener",
6392
+ error
6393
+ );
6394
+ });
6395
+ };
6396
+ }
6397
+ executeBatchOperationsAsync(operations, validateOnly) {
6398
+ return this.rpcClient.call(
6399
+ "H5_SIMULATION_BATCH_OPERATIONS" /* H5_SIMULATION_BATCH_OPERATIONS */,
6400
+ {
6401
+ operations,
6402
+ validateOnly
6403
+ }
6404
+ );
6788
6405
  }
6789
- async createRoom(options) {
6406
+ async getAvailableItemsAsync(containerId, slotId) {
6790
6407
  const response = await this.rpcClient.call(
6791
- "H5_ROOM_CREATE" /* H5_ROOM_CREATE */,
6408
+ "H5_SIMULATION_GET_AVAILABLE_ITEMS" /* H5_SIMULATION_GET_AVAILABLE_ITEMS */,
6792
6409
  {
6793
- options
6410
+ containerId,
6411
+ slotId
6412
+ }
6413
+ );
6414
+ return response.availableItems || [];
6415
+ }
6416
+ calculatePowerPreviewAsync(containerId, slotId, candidateItemId) {
6417
+ return this.rpcClient.call(
6418
+ "H5_SIMULATION_CALCULATE_POWER_PREVIEW" /* H5_SIMULATION_CALCULATE_POWER_PREVIEW */,
6419
+ {
6420
+ containerId,
6421
+ slotId,
6422
+ candidateItemId
6423
+ }
6424
+ );
6425
+ }
6426
+ assignItemToSlotAsync(containerId, slotId, itemId) {
6427
+ return this.rpcClient.call(
6428
+ "H5_SIMULATION_ASSIGN_ITEM" /* H5_SIMULATION_ASSIGN_ITEM */,
6429
+ {
6430
+ containerId,
6431
+ slotId,
6432
+ itemId
6433
+ }
6434
+ );
6435
+ }
6436
+ removeItemFromSlotAsync(containerId, slotId) {
6437
+ return this.rpcClient.call(
6438
+ "H5_SIMULATION_REMOVE_ITEM" /* H5_SIMULATION_REMOVE_ITEM */,
6439
+ {
6440
+ containerId,
6441
+ slotId
6794
6442
  }
6795
6443
  );
6796
- if (response.success === false) {
6797
- throw new Error(response.error || "Failed to create room");
6798
- }
6799
- const roomData = response.roomData || response;
6800
- const room = new VenusRoom(roomData);
6801
- return room;
6802
6444
  }
6803
- async joinOrCreateRoom(options) {
6445
+ async getSlotContainersAsync() {
6804
6446
  const response = await this.rpcClient.call(
6805
- "H5_ROOM_JOIN_OR_CREATE" /* H5_ROOM_JOIN_OR_CREATE */,
6447
+ "H5_SIMULATION_GET_CONTAINERS" /* H5_SIMULATION_GET_CONTAINERS */,
6448
+ {}
6449
+ );
6450
+ return response.containers || [];
6451
+ }
6452
+ async getSlotAssignmentsAsync(containerId) {
6453
+ const response = await this.rpcClient.call(
6454
+ "H5_SIMULATION_GET_ASSIGNMENTS" /* H5_SIMULATION_GET_ASSIGNMENTS */,
6806
6455
  {
6807
- options
6456
+ containerId
6808
6457
  }
6809
6458
  );
6810
- if (response.success === false) {
6811
- throw new Error(response.error || "Failed to join or create room");
6812
- }
6813
- const data = response.value || response;
6814
- const room = new VenusRoom(data.roomData);
6815
- return {
6816
- action: data.action,
6817
- room,
6818
- playersJoined: data.playersJoined
6819
- };
6459
+ return Array.isArray(response) ? response : response.assignments || [];
6820
6460
  }
6821
- async joinRoomByCode(roomCode) {
6461
+ async getStateAsync(roomId) {
6822
6462
  const response = await this.rpcClient.call(
6823
- "H5_ROOM_JOIN_BY_CODE" /* H5_ROOM_JOIN_BY_CODE */,
6463
+ "H5_SIMULATION_GET_STATE" /* H5_SIMULATION_GET_STATE */,
6824
6464
  {
6825
- roomCode
6465
+ roomId
6826
6466
  }
6827
6467
  );
6828
- if (response?.success === false) {
6829
- throw new Error(response.error || "Failed to join room by code");
6468
+ if (response.configuration) {
6469
+ this._simulationConfig = response.configuration;
6830
6470
  }
6831
- const roomData = response.roomData || response;
6832
- const room = new VenusRoom(roomData);
6833
- return room;
6471
+ return response;
6834
6472
  }
6835
- // Get user's rooms with optional filtering
6836
- async getUserRooms(includeArchived = false) {
6837
- const response = await this.rpcClient.call(
6838
- "H5_ROOM_GET_USER_ROOMS" /* H5_ROOM_GET_USER_ROOMS */,
6473
+ async getConfigAsync(roomId) {
6474
+ if (this._simulationConfig) {
6475
+ return this._simulationConfig;
6476
+ }
6477
+ const config = await this.rpcClient.call(
6478
+ "H5_SIMULATION_GET_CONFIG" /* H5_SIMULATION_GET_CONFIG */,
6839
6479
  {
6840
- includeArchived
6480
+ roomId
6841
6481
  }
6842
6482
  );
6843
- if (response?.success === false) {
6844
- throw new Error(response.error || "Failed to get user rooms");
6483
+ if (config) {
6484
+ this._simulationConfig = config;
6485
+ return config;
6845
6486
  }
6846
- const rawRooms = response.rooms || [];
6847
- const venusRooms = [];
6848
- for (const roomData of rawRooms) {
6849
- if (!roomData.id) {
6850
- console.warn("getUserRooms: Skipping room with missing ID:", roomData);
6851
- continue;
6487
+ throw new Error("No simulation configuration available");
6488
+ }
6489
+ executeRecipeAsync(recipeId, inputs, options) {
6490
+ return this.rpcClient.call(
6491
+ "H5_SIMULATION_EXECUTE_RECIPE" /* H5_SIMULATION_EXECUTE_RECIPE */,
6492
+ {
6493
+ recipeId,
6494
+ inputs,
6495
+ roomId: options?.roomId,
6496
+ batchAmount: options?.batchAmount,
6497
+ allowPartialBatch: options?.allowPartialBatch,
6498
+ entity: options?.entity
6852
6499
  }
6853
- try {
6854
- const venusRoom = new VenusRoom(roomData);
6855
- venusRooms.push(venusRoom);
6856
- } catch (error) {
6857
- console.warn(
6858
- "getUserRooms: Failed to create VenusRoom object:",
6859
- error,
6860
- roomData
6861
- );
6500
+ );
6501
+ }
6502
+ collectRecipeAsync(runId) {
6503
+ return this.rpcClient.call("H5_SIMULATION_COLLECT_RECIPE" /* H5_SIMULATION_COLLECT_RECIPE */, {
6504
+ runId
6505
+ });
6506
+ }
6507
+ getActiveRunsAsync(options) {
6508
+ return this.rpcClient.call(
6509
+ "H5_SIMULATION_GET_ACTIVE_RUNS" /* H5_SIMULATION_GET_ACTIVE_RUNS */,
6510
+ {
6511
+ roomId: options?.roomId
6862
6512
  }
6863
- }
6864
- return venusRooms;
6513
+ );
6865
6514
  }
6866
- async updateData(room, updates, merge = true) {
6867
- const response = await this.rpcClient.call(
6868
- "H5_ROOM_UPDATE_DATA" /* H5_ROOM_UPDATE_DATA */,
6515
+ executeScopedRecipeAsync(recipeId, entity, inputs, options) {
6516
+ return this.rpcClient.call(
6517
+ "H5_SIMULATION_EXECUTE_SCOPED_RECIPE" /* H5_SIMULATION_EXECUTE_SCOPED_RECIPE */,
6869
6518
  {
6870
- roomId: room.id,
6871
- updates,
6872
- merge
6519
+ recipeId,
6520
+ entity,
6521
+ inputs,
6522
+ roomId: options?.roomId ?? null,
6523
+ options
6873
6524
  }
6874
6525
  );
6875
- if (response?.success === false) {
6876
- throw new Error(response.error || "Failed to update room data");
6877
- }
6878
- return response.data;
6879
6526
  }
6880
- async getData(room) {
6881
- const response = await this.rpcClient.call(
6882
- "H5_ROOM_GET_DATA" /* H5_ROOM_GET_DATA */,
6527
+ getAvailableRecipesAsync(options) {
6528
+ return this.rpcClient.call(
6529
+ "H5_SIMULATION_GET_AVAILABLE_RECIPES" /* H5_SIMULATION_GET_AVAILABLE_RECIPES */,
6883
6530
  {
6884
- roomId: room.id
6531
+ roomId: options?.roomId || null,
6532
+ includeActorRecipes: options?.includeActorRecipes || false
6885
6533
  }
6886
6534
  );
6887
- if (response?.success === false) {
6888
- throw new Error(response.error || "Failed to get room data");
6889
- }
6890
- return response.data;
6891
6535
  }
6892
- async sendMessage(venusRoom, messageData) {
6893
- const response = await this.rpcClient.call(
6894
- "H5_ROOM_SEND_MESSAGE" /* H5_ROOM_SEND_MESSAGE */,
6536
+ getRecipeRequirementsAsync(recipe) {
6537
+ return this.rpcClient.call(
6538
+ "H5_SIMULATION_GET_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_RECIPE_REQUIREMENTS */,
6895
6539
  {
6896
- roomId: venusRoom.id,
6897
- message: messageData
6540
+ recipeId: recipe.recipeId,
6541
+ entity: recipe.entity,
6542
+ batchAmount: recipe.batchAmount
6898
6543
  }
6899
6544
  );
6900
- if (response?.success === false) {
6901
- throw new Error(response.error || "Failed to send message");
6902
- }
6903
- return response.messageId;
6904
6545
  }
6905
- async leave(room) {
6906
- const response = await this.rpcClient.call(
6907
- "H5_ROOM_LEAVE" /* H5_ROOM_LEAVE */,
6546
+ getBatchRecipeRequirementsAsync(recipes) {
6547
+ return this.rpcClient.call(
6548
+ "H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS */,
6908
6549
  {
6909
- roomId: room.id
6550
+ recipes
6910
6551
  }
6911
6552
  );
6912
- if (response?.success === false) {
6913
- throw new Error(response.error || "Failed to leave room");
6914
- }
6915
- return response;
6916
6553
  }
6917
- async startGame(room, gameConfig = {}, turnOrder = null) {
6918
- const response = await this.rpcClient.call(
6919
- "H5_ROOM_START_GAME" /* H5_ROOM_START_GAME */,
6554
+ triggerRecipeChainAsync(recipeId, options) {
6555
+ return this.rpcClient.call(
6556
+ "H5_SIMULATION_TRIGGER_RECIPE_CHAIN" /* H5_SIMULATION_TRIGGER_RECIPE_CHAIN */,
6920
6557
  {
6921
- roomId: room.id,
6922
- gameConfig,
6923
- turnOrder
6558
+ triggerRecipeId: recipeId,
6559
+ context: options?.context,
6560
+ roomId: options?.roomId
6924
6561
  }
6925
6562
  );
6926
- if (response?.success === false) {
6927
- throw new Error(response.error || "Failed to start game");
6928
- }
6929
- return response.data;
6930
6563
  }
6931
- async proposeMove(room, proposalPayload) {
6932
- const response = await this.rpcClient.call(
6933
- "h5:room:proposeMove" /* H5_ROOM_PROPOSE_MOVE */,
6564
+ getEntityMetadataAsync(entityId) {
6565
+ return this.rpcClient.call(
6566
+ "H5_SIMULATION_GET_ENTITY_METADATA" /* H5_SIMULATION_GET_ENTITY_METADATA */,
6934
6567
  {
6935
- roomId: room.id,
6936
- gameSpecificState: proposalPayload.gameSpecificState,
6937
- moveType: proposalPayload.moveType,
6938
- clientContext: proposalPayload.clientContext,
6939
- clientProposalId: proposalPayload.clientProposalId
6568
+ entityId
6940
6569
  }
6941
6570
  );
6942
- if (response?.success === false) {
6943
- throw new Error(response.error || "Failed to propose move");
6944
- }
6945
- return response.data;
6946
6571
  }
6947
- async validateMove(room, moveId, isValid, reason = null, validatorId = null) {
6948
- console.log(`[Venus Rooms] Validating move ${moveId}: ${isValid}`);
6949
- return { success: true, moveId, isValid, reason };
6572
+ async resolveFieldValueAsync(entityId, fieldPath, entity) {
6573
+ const response = await this.rpcClient.call(
6574
+ "H5_SIMULATION_RESOLVE_VALUE" /* H5_SIMULATION_RESOLVE_VALUE */,
6575
+ {
6576
+ entityId,
6577
+ fieldPath,
6578
+ entity
6579
+ }
6580
+ );
6581
+ return response.value;
6950
6582
  }
6951
- async roomSubscribeToGameEvents(room, callback) {
6952
- "game_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
6953
- if (!this.subscriptions.gameEvents[room.id]) {
6954
- this.subscriptions.gameEvents[room.id] = [];
6583
+ handleSimulationUpdate(notification) {
6584
+ if (!notification || !notification.subscriptionId) {
6585
+ console.warn("[Venus SDK] Received malformed simulation update");
6586
+ return;
6955
6587
  }
6956
- this.subscriptions.gameEvents[room.id].push(callback);
6957
- }
6958
- subscribe(room, options = {}) {
6959
- const subscriptionIds = [];
6960
- const roomId = room.id;
6961
- if (options.onData) {
6962
- const dataSubId = "data_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
6963
- if (!this.subscriptions.data[roomId]) {
6964
- this.subscriptions.data[roomId] = [];
6965
- }
6966
- this.subscriptions.data[roomId].push(options.onData);
6967
- subscriptionIds.push({
6968
- type: "data",
6969
- id: dataSubId,
6970
- callback: options.onData
6971
- });
6588
+ const callback = this.subscriptionCallbacks.get(notification.subscriptionId);
6589
+ if (!callback) {
6590
+ console.warn(
6591
+ "[Venus SDK] Received update for unknown subscription:",
6592
+ notification.subscriptionId
6593
+ );
6594
+ return;
6972
6595
  }
6973
- if (options.onMessages) {
6974
- const msgSubId = "messages_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
6975
- if (!this.subscriptions.messages[roomId]) {
6976
- this.subscriptions.messages[roomId] = [];
6977
- }
6978
- this.subscriptions.messages[roomId].push(options.onMessages);
6979
- subscriptionIds.push({
6980
- type: "messages",
6981
- id: msgSubId,
6982
- callback: options.onMessages
6983
- });
6596
+ try {
6597
+ callback(notification.updates);
6598
+ } catch (error) {
6599
+ console.error("[Venus SDK] Error in simulation subscription callback", error);
6984
6600
  }
6985
- if (options.onMoves || options.onGameEvents) {
6986
- const handler = options.onMoves || options.onGameEvents;
6987
- if (handler) {
6988
- const gameSubId = "game_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
6989
- if (!this.subscriptions.gameEvents[roomId]) {
6990
- this.subscriptions.gameEvents[roomId] = [];
6991
- }
6992
- this.subscriptions.gameEvents[roomId].push(handler);
6993
- subscriptionIds.push({
6994
- type: "gameEvents",
6995
- id: gameSubId,
6996
- callback: handler
6997
- });
6998
- }
6601
+ }
6602
+ ensureValidSubscribeOptions(options) {
6603
+ if (typeof options !== "object" || options === null) {
6604
+ throw new Error("Simulation subscribe requires an options object");
6999
6605
  }
7000
- const needsSubscription = subscriptionIds.length > 0 && (this.subscriptions.data[roomId]?.length ?? 0) <= 1 && (this.subscriptions.messages[roomId]?.length ?? 0) <= 1 && (this.subscriptions.gameEvents[roomId]?.length ?? 0) <= 1;
7001
- if (needsSubscription) {
7002
- this.rpcClient.call("H5_ROOM_SUBSCRIBE" /* H5_ROOM_SUBSCRIBE */, {
7003
- roomId,
7004
- subscribeToData: !!options.onData,
7005
- subscribeToMessages: !!options.onMessages,
7006
- subscribeToProposedMoves: !!(options.onMoves || options.onGameEvents)
7007
- }).catch((error) => {
7008
- console.error("Failed to set up room subscription:", error);
7009
- });
6606
+ const opts = options;
6607
+ if (typeof opts.onUpdate !== "function") {
6608
+ throw new Error("Simulation subscribe requires an onUpdate callback");
6609
+ }
6610
+ const hasFilter = Array.isArray(opts.entities) && opts.entities.length > 0 || Array.isArray(opts.tags) && opts.tags.length > 0 || Boolean(opts.activeRuns);
6611
+ if (!hasFilter) {
6612
+ throw new Error(
6613
+ "Simulation subscribe requires at least one filter (entities, tags, activeRuns)"
6614
+ );
7010
6615
  }
7011
- let called = false;
7012
- return () => {
7013
- if (called) return;
7014
- called = true;
7015
- subscriptionIds.forEach((sub) => {
7016
- const bucket = this.subscriptions[sub.type];
7017
- const callbacks = bucket && bucket[roomId] || [];
7018
- const index = callbacks.indexOf(sub.callback);
7019
- if (index > -1) callbacks.splice(index, 1);
7020
- });
7021
- const hasNoCallbacks = (this.subscriptions.data[roomId]?.length ?? 0) === 0 && (this.subscriptions.messages[roomId]?.length ?? 0) === 0 && (this.subscriptions.gameEvents[roomId]?.length ?? 0) === 0;
7022
- if (hasNoCallbacks) {
7023
- this.rpcClient.call("H5_ROOM_UNSUBSCRIBE" /* H5_ROOM_UNSUBSCRIBE */, {
7024
- roomId
7025
- }).catch((error) => {
7026
- console.error("Failed to clean up room subscription:", error);
7027
- });
7028
- }
7029
- };
7030
6616
  }
7031
6617
  };
7032
6618
 
6619
+ // src/simulation/index.ts
6620
+ function initializeSimulation(venusApi, host) {
6621
+ venusApi.simulation = {
6622
+ isEnabled: () => true
6623
+ };
6624
+ venusApi.simulation.getConfigAsync = () => {
6625
+ return host.simulation.getConfigAsync();
6626
+ };
6627
+ venusApi.simulation.getStateAsync = (roomId) => {
6628
+ return host.simulation.getStateAsync(roomId);
6629
+ };
6630
+ venusApi.simulation.executeRecipeAsync = (recipeId, inputs, options) => {
6631
+ return host.simulation.executeRecipeAsync(recipeId, inputs, options);
6632
+ };
6633
+ venusApi.simulation.getActiveRunsAsync = () => {
6634
+ return host.simulation.getActiveRunsAsync();
6635
+ };
6636
+ venusApi.simulation.collectRecipeAsync = (runId) => {
6637
+ return host.simulation.collectRecipeAsync(runId);
6638
+ };
6639
+ venusApi.simulation.executeScopedRecipeAsync = (recipeId, entity, inputs, options) => {
6640
+ return host.simulation.executeScopedRecipeAsync(recipeId, entity, inputs, options);
6641
+ };
6642
+ venusApi.simulation.triggerRecipeChainAsync = (recipeId, options) => {
6643
+ return host.simulation.triggerRecipeChainAsync(recipeId, options);
6644
+ };
6645
+ venusApi.simulation.getAvailableRecipesAsync = async (options) => {
6646
+ return host.simulation.getAvailableRecipesAsync(options);
6647
+ };
6648
+ venusApi.simulation.getRecipeRequirementsAsync = (recipe) => {
6649
+ return host.simulation.getRecipeRequirementsAsync(recipe);
6650
+ };
6651
+ venusApi.simulation.getBatchRecipeRequirementsAsync = (recipes) => {
6652
+ return host.simulation.getBatchRecipeRequirementsAsync(recipes);
6653
+ };
6654
+ venusApi.simulation.resolveFieldValueAsync = (entityId, fieldPath, entity) => {
6655
+ return host.simulation.resolveFieldValueAsync(entityId, fieldPath, entity);
6656
+ };
6657
+ venusApi.simulation.getEntityMetadataAsync = (entityId) => {
6658
+ return host.simulation.getEntityMetadataAsync(entityId);
6659
+ };
6660
+ venusApi.simulation.getSlotAssignmentsAsync = (containerId) => {
6661
+ return host.simulation.getSlotAssignmentsAsync(containerId);
6662
+ };
6663
+ venusApi.simulation.getSlotContainersAsync = () => {
6664
+ return host.simulation.getSlotContainersAsync();
6665
+ };
6666
+ venusApi.simulation.assignItemToSlotAsync = (containerId, slotId, itemId) => {
6667
+ return host.simulation.assignItemToSlotAsync(containerId, slotId, itemId);
6668
+ };
6669
+ venusApi.simulation.removeItemFromSlotAsync = (containerId, slotId) => {
6670
+ return host.simulation.removeItemFromSlotAsync(containerId, slotId);
6671
+ };
6672
+ venusApi.simulation.getAvailableItemsAsync = (containerId, slotId) => {
6673
+ return host.simulation.getAvailableItemsAsync(containerId, slotId);
6674
+ };
6675
+ venusApi.simulation.calculatePowerPreviewAsync = (containerId, slotId, candidateItemId) => {
6676
+ return host.simulation.calculatePowerPreviewAsync(
6677
+ containerId,
6678
+ slotId,
6679
+ candidateItemId
6680
+ );
6681
+ };
6682
+ venusApi.simulation.executeBatchOperationsAsync = (operations, validateOnly) => {
6683
+ return host.simulation.executeBatchOperationsAsync(operations, validateOnly);
6684
+ };
6685
+ venusApi.simulation.validateSlotAssignmentAsync = (containerId, slotId, itemId) => {
6686
+ return host.simulation.validateSlotAssignmentAsync(
6687
+ containerId,
6688
+ slotId,
6689
+ itemId
6690
+ );
6691
+ };
6692
+ }
6693
+
7033
6694
  // src/social/RpcSocialApi.ts
7034
6695
  var RpcSocialApi = class {
7035
6696
  constructor(rpcClient) {
@@ -7076,9 +6737,9 @@ var RemoteHost = class {
7076
6737
  __publicField(this, "notifications");
7077
6738
  __publicField(this, "popups");
7078
6739
  __publicField(this, "profile");
6740
+ __publicField(this, "system");
7079
6741
  __publicField(this, "cdn");
7080
6742
  __publicField(this, "time");
7081
- __publicField(this, "post");
7082
6743
  __publicField(this, "ai");
7083
6744
  __publicField(this, "haptics");
7084
6745
  __publicField(this, "features");
@@ -7132,10 +6793,12 @@ var RemoteHost = class {
7132
6793
  this.navigation = new RpcNavigationApi(rpcClient, venusApi);
7133
6794
  this.notifications = new RpcNotificationsApi(rpcClient);
7134
6795
  this.popups = new RpcPopupsApi(rpcClient);
7135
- this.profile = new HostProfileApi();
6796
+ this.profile = new HostProfileApi(venusApi);
6797
+ const deviceApi = new HostDeviceApi(venusApi);
6798
+ const environmentApi = new HostEnvironmentApi(venusApi);
6799
+ this.system = new HostSystemApi(deviceApi, environmentApi, venusApi);
7136
6800
  this.cdn = new HostCdnApi(getCdnBaseUrl());
7137
- this.time = new HostTimeApi(rpcClient);
7138
- this.post = new RpcPostApi(rpcClient);
6801
+ this.time = new HostTimeApi(rpcClient, venusApi);
7139
6802
  this.ai = new RpcAiApi(rpcClient);
7140
6803
  this.haptics = new RpcHapticsApi(rpcClient);
7141
6804
  this.features = new RpcFeaturesApi(rpcClient);
@@ -7150,7 +6813,6 @@ var RemoteHost = class {
7150
6813
  venusApi.isMock = () => false;
7151
6814
  this.venusApi.sharedAssets = new RpcSharedAssetsApi(rpcClient, venusApi);
7152
6815
  initializeRoomsApi(this.venusApi, this);
7153
- console.log("[Venus SDK] Remote host created");
7154
6816
  }
7155
6817
  get isInitialized() {
7156
6818
  return this._isInitialized;
@@ -7169,35 +6831,27 @@ var RemoteHost = class {
7169
6831
  );
7170
6832
  transport.instanceId = response.instanceId;
7171
6833
  this.log(`Remote Host Initialized with id: ${transport.instanceId}`);
7172
- if (response.profile) {
7173
- const profile = response.profile;
7174
- const sanitizedProfile = {
7175
- id: profile.id,
7176
- username: profile.username,
7177
- avatarUrl: profile.avatarUrl ?? null,
7178
- isAnonymous: Boolean(profile.isAnonymous)
7179
- };
7180
- if (typeof window !== "undefined") {
7181
- const globalWindow = window;
7182
- const venus = globalWindow.venus || (globalWindow.venus = {});
7183
- venus.profile = sanitizedProfile;
7184
- if (venus._config) {
7185
- venus._config.profile = sanitizedProfile;
7186
- }
7187
- if (venus.config) {
7188
- venus.config.profile = sanitizedProfile;
7189
- }
7190
- }
7191
- }
6834
+ const profile = response.profile;
6835
+ const sanitizedProfile = {
6836
+ id: profile.id,
6837
+ username: profile.username,
6838
+ avatarUrl: profile.avatarUrl ?? null,
6839
+ isAnonymous: Boolean(profile.isAnonymous)
6840
+ };
6841
+ this.venusApi._profileData = sanitizedProfile;
6842
+ this.venusApi._deviceData = response.device;
6843
+ this.venusApi._environmentData = response.environment;
6844
+ this.venusApi._localeData = response.locale;
6845
+ this.venusApi._languageCodeData = response.languageCode;
7192
6846
  this._isInitialized = true;
7193
- this.venusApi.launchParams = response.launchParams || {};
6847
+ this.venusApi.launchParams = response.launchParams;
7194
6848
  await this.rpcClient.call("READY" /* READY */, {});
7195
- const hudInsets = response.hudInsets;
7196
- if (hudInsets) {
7197
- this.venusApi.config.ui.safeArea = hudInsets;
6849
+ const safeArea = response.safeArea;
6850
+ if (safeArea) {
6851
+ this.venusApi._safeAreaData = safeArea;
7198
6852
  }
7199
6853
  return {
7200
- hudInsets,
6854
+ safeArea,
7201
6855
  initializeAsleep: response.initializeAsleep
7202
6856
  };
7203
6857
  }
@@ -7209,19 +6863,14 @@ var RemoteHost = class {
7209
6863
  // src/Host.ts
7210
6864
  function createHost(venusApi, isMock) {
7211
6865
  if (isMock) {
7212
- console.log("[Venus SDK] Creating Local Host");
7213
6866
  return new MockHost(venusApi);
7214
6867
  } else {
7215
- console.log("[Venus SDK] Creating Remote Host");
7216
6868
  return new RemoteHost(venusApi);
7217
6869
  }
7218
6870
  }
7219
6871
 
7220
- // src/venus-api/index.js
7221
- init_rooms();
7222
-
7223
6872
  // src/version.ts
7224
- var SDK_VERSION = "3.0.4";
6873
+ var SDK_VERSION = "3.2.0";
7225
6874
 
7226
6875
  // src/social/index.ts
7227
6876
  function initializeSocial(venusApi, host) {
@@ -7271,82 +6920,8 @@ var VenusAPI2 = class {
7271
6920
  bottom: 10,
7272
6921
  left: 0
7273
6922
  },
7274
- uiControls: {
7275
- closeButton: { x: 16, y: 16, width: 32, height: 32 },
7276
- menuButton: { x: window.innerWidth - 48, y: 16, width: 32, height: 32 },
7277
- feedHeader: { x: 0, y: 0, width: window.innerWidth, height: 66 },
7278
- playButton: {
7279
- x: 0,
7280
- y: window.innerHeight - 60,
7281
- width: window.innerWidth,
7282
- height: 60
7283
- }
7284
- },
7285
- // Complete theme structure (matching createH5Theme output)
7286
- theme: {
7287
- background: {
7288
- default: "#131419",
7289
- muted: "#1b1d25",
7290
- dark: "#0d0e11"
7291
- },
7292
- text: {
7293
- primary: "#ffffff",
7294
- muted: "#808080",
7295
- inverted: "#000000"
7296
- },
7297
- theme: {
7298
- primary: "#f6c833",
7299
- secondary: "#6366f1",
7300
- background: "#131419",
7301
- border: "#262626",
7302
- card: "#1b1d25",
7303
- "card-glass": "rgba(27, 29, 37, 0.8)"
7304
- },
7305
- typography: {
7306
- fontFamily: {
7307
- base: "Plus Jakarta Sans, Roboto, sans-serif",
7308
- heading: "Plus Jakarta Sans, Roboto, sans-serif",
7309
- mono: "monospace"
7310
- },
7311
- fontSize: {
7312
- "2xs": "10px",
7313
- xs: "12px",
7314
- sm: "14px",
7315
- md: "16px",
7316
- lg: "18px",
7317
- xl: "20px",
7318
- "2xl": "24px",
7319
- "3xl": "30px",
7320
- "4xl": "36px",
7321
- "5xl": "48px",
7322
- "6xl": "60px"
7323
- },
7324
- fontWeight: {
7325
- thin: "100",
7326
- extralight: "200",
7327
- light: "300",
7328
- regular: "400",
7329
- medium: "500",
7330
- semibold: "600",
7331
- bold: "700",
7332
- extrabold: "800",
7333
- black: "900",
7334
- extrablack: "950"
7335
- },
7336
- lineHeight: {
7337
- none: "1",
7338
- tight: "1.25",
7339
- snug: "1.375",
7340
- normal: "1.5",
7341
- relaxed: "1.625",
7342
- loose: "2"
7343
- }
7344
- }
7345
- },
7346
- // Static locale data at top level
7347
- locale: "en-US",
7348
- languageCode: "en",
7349
- // Note: Profile is now separate from config and accessed via getCurrentProfile()
6923
+ // NOTE: locale and languageCode are NOT part of static config
6924
+ // They are delivered via INIT_SDK handshake and accessed via getLocale()/getLanguageCode()
7350
6925
  // Complete environment info (matching buildStaticConfig)
7351
6926
  environment: {
7352
6927
  isDevelopment: true,
@@ -7400,12 +6975,6 @@ var VenusAPI2 = class {
7400
6975
  onHide: null,
7401
6976
  onShow: null
7402
6977
  },
7403
- currentPostInteractions: {
7404
- isLiked: false,
7405
- isFollowing: false,
7406
- likesCount: 42,
7407
- commentsCount: 7
7408
- },
7409
6978
  // Platform overrides for testing different environments
7410
6979
  platformOverrides: {
7411
6980
  isMobile: true,
@@ -7414,117 +6983,74 @@ var VenusAPI2 = class {
7414
6983
  };
7415
6984
  this._detectHostedEnvironment();
7416
6985
  this.launchParams = {};
7417
- this.config = createProxiedObject.call(this, "config", {
7418
- locale: "en-US",
7419
- languageCode: "en",
7420
- // Note: Profile is no longer in config - use getCurrentProfile() instead
7421
- environment: {
7422
- isDevelopment: true,
7423
- platform: typeof navigator !== "undefined" ? navigator.platform : "unknown",
7424
- platformVersion: "unknown",
7425
- browserInfo: {
7426
- browser: "unknown",
7427
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "unknown",
7428
- isMobile: true,
7429
- isTablet: false,
7430
- language: typeof navigator !== "undefined" ? navigator.language : "en-US"
6986
+ this.config = createProxiedObject.call(this, "config", {});
6987
+ const originalConfig = this.config;
6988
+ this.config = new Proxy(originalConfig, {
6989
+ get(target, prop) {
6990
+ if (prop === "locale") {
6991
+ throw new Error("Use VenusAPI.getLocale() instead.");
6992
+ }
6993
+ if (prop === "languageCode") {
6994
+ throw new Error("Use VenusAPI.getLanguageCode() instead.");
6995
+ }
6996
+ if (prop === "user") {
6997
+ throw new Error("Use VenusAPI.getLocale() and VenusAPI.getLanguageCode() instead.");
6998
+ }
6999
+ if (prop === "device") {
7000
+ throw new Error("Use VenusAPI.system.getDevice() instead.");
7001
+ }
7002
+ if (prop === "environment") {
7003
+ throw new Error("Use VenusAPI.system.getEnvironment() instead.");
7004
+ }
7005
+ if (prop === "profile") {
7006
+ throw new Error("Use VenusAPI.getProfile() instead.");
7007
+ }
7008
+ if (prop === "rooms") {
7009
+ throw new Error("Rooms configuration is internal. Use VenusAPI.rooms methods instead.");
7010
+ }
7011
+ if (prop === "ui") {
7012
+ return new Proxy({}, {
7013
+ get(uiTarget, uiProp) {
7014
+ if (uiProp === "safeArea") {
7015
+ throw new Error("Use VenusAPI.system.getSafeArea() instead.");
7016
+ }
7017
+ if (uiProp === "hudInsets") {
7018
+ throw new Error("Use VenusAPI.system.getSafeArea() instead.");
7019
+ }
7020
+ if (uiProp === "controls") {
7021
+ throw new Error("UI controls are no longer supported.");
7022
+ }
7023
+ throw new Error(`VenusAPI.config.ui.${uiProp} is not supported.`);
7024
+ }
7025
+ });
7431
7026
  }
7027
+ return target[prop];
7432
7028
  },
7433
- ui: {
7434
- controls: {
7435
- closeButton: { x: 16, y: 16, width: 32, height: 32 },
7436
- menuButton: {
7437
- x: typeof window !== "undefined" ? window.innerWidth - 48 : 352,
7438
- y: 16,
7439
- width: 32,
7440
- height: 32
7441
- },
7442
- feedHeader: {
7443
- x: 0,
7444
- y: 0,
7445
- width: typeof window !== "undefined" ? window.innerWidth : 400,
7446
- height: 66
7447
- },
7448
- playButton: {
7449
- x: 0,
7450
- y: typeof window !== "undefined" ? window.innerHeight - 60 : 740,
7451
- width: typeof window !== "undefined" ? window.innerWidth : 400,
7452
- height: 60
7453
- }
7454
- },
7455
- safeArea: { top: 44, left: 0, right: 0, bottom: 34 },
7456
- hudInsets: {
7457
- preview: { top: 60, left: 0, right: 0, bottom: 40 },
7458
- fullscreen: { top: 44, left: 0, right: 0, bottom: 34 }
7029
+ set(target, prop, value) {
7030
+ if (prop === "locale" || prop === "languageCode" || prop === "user" || prop === "device" || prop === "environment" || prop === "profile") {
7031
+ throw new Error(`VenusAPI.config.${prop} cannot be set. Configuration is read-only.`);
7032
+ }
7033
+ if (prop === "ui") {
7034
+ console.warn("[Venus SDK] Cannot set config.ui");
7035
+ return true;
7459
7036
  }
7037
+ target[prop] = value;
7038
+ return true;
7460
7039
  },
7461
- device: {
7462
- screenSize: {
7463
- width: typeof window !== "undefined" ? window.screen?.width || 0 : 0,
7464
- height: typeof window !== "undefined" ? window.screen?.height || 0 : 0
7465
- },
7466
- viewportSize: {
7467
- width: typeof window !== "undefined" ? window.innerWidth : 0,
7468
- height: typeof window !== "undefined" ? window.innerHeight : 0
7469
- },
7470
- orientation: "portrait",
7471
- pixelRatio: typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1,
7472
- fontScale: 1,
7473
- deviceType: "phone",
7474
- hapticsEnabled: false,
7475
- haptics: { supported: false, enabled: false }
7040
+ has(target, prop) {
7041
+ if (prop === "ui") {
7042
+ return false;
7043
+ }
7044
+ return prop in target;
7476
7045
  },
7477
- theme: {
7478
- background: { default: "#131419", muted: "#1b1d25", dark: "#0d0e11" },
7479
- text: { primary: "#ffffff", muted: "#808080", inverted: "#000000" },
7480
- theme: {
7481
- primary: "#f6c833",
7482
- secondary: "#6366f1",
7483
- background: "#131419",
7484
- border: "#262626",
7485
- card: "#1b1d25",
7486
- "card-glass": "rgba(27, 29, 37, 0.8)"
7487
- },
7488
- typography: {
7489
- fontFamily: {
7490
- base: "Plus Jakarta Sans, Roboto, sans-serif",
7491
- heading: "Plus Jakarta Sans, Roboto, sans-serif",
7492
- mono: "monospace"
7493
- },
7494
- fontSize: {
7495
- "2xs": "10px",
7496
- xs: "12px",
7497
- sm: "14px",
7498
- md: "16px",
7499
- lg: "18px",
7500
- xl: "20px",
7501
- "2xl": "24px",
7502
- "3xl": "30px",
7503
- "4xl": "36px",
7504
- "5xl": "48px",
7505
- "6xl": "60px"
7506
- },
7507
- fontWeight: {
7508
- thin: "100",
7509
- extralight: "200",
7510
- light: "300",
7511
- regular: "400",
7512
- medium: "500",
7513
- semibold: "600",
7514
- bold: "700",
7515
- extrabold: "800",
7516
- black: "900",
7517
- extrablack: "950"
7518
- },
7519
- lineHeight: {
7520
- none: "1",
7521
- tight: "1.25",
7522
- snug: "1.375",
7523
- normal: "1.5",
7524
- relaxed: "1.625",
7525
- loose: "2"
7526
- }
7046
+ ownKeys(target) {
7047
+ return Reflect.ownKeys(target).filter((key) => key !== "ui");
7048
+ },
7049
+ getOwnPropertyDescriptor(target, prop) {
7050
+ if (prop === "ui") {
7051
+ return void 0;
7527
7052
  }
7053
+ return Reflect.getOwnPropertyDescriptor(target, prop);
7528
7054
  }
7529
7055
  });
7530
7056
  const isInsideHostedEnv = this._bootstrap.isInsideHostedEnvironment;
@@ -7533,7 +7059,6 @@ var VenusAPI2 = class {
7533
7059
  initializeStorage(this, host);
7534
7060
  initializeRoomsApi(this, host);
7535
7061
  initializeAds(this, host);
7536
- initializeTheme(this);
7537
7062
  initializePopups(this, host);
7538
7063
  initializeAnalytics(this, host);
7539
7064
  initializeIap(this, host);
@@ -7548,15 +7073,31 @@ var VenusAPI2 = class {
7548
7073
  initializeLoggingApi(this, host);
7549
7074
  const isAvatar3dDisabled = typeof window !== "undefined" && window.location.search.includes("EXPO_PUBLIC_DISABLE_3D_AVATARS=true");
7550
7075
  initializeProfile(this, host);
7076
+ initializeSystem(this, host);
7551
7077
  if (!isAvatar3dDisabled) {
7552
7078
  initializeAvatar3d(this, host);
7553
7079
  }
7554
7080
  initializeStackNavigation(this, host);
7555
- initializePost(this, host);
7556
7081
  initializeAi(this, host);
7557
7082
  initializeSimulation(this, host);
7558
7083
  initializeSocial(this, host);
7559
7084
  initializeAssetLoader(this, createProxiedMethod);
7085
+ this.getLocale = () => {
7086
+ if (this._localeData) {
7087
+ return this._localeData;
7088
+ }
7089
+ if (typeof navigator !== "undefined" && navigator.language) {
7090
+ return navigator.language;
7091
+ }
7092
+ return "en-US";
7093
+ };
7094
+ this.getLanguageCode = () => {
7095
+ if (this._languageCodeData) {
7096
+ return this._languageCodeData;
7097
+ }
7098
+ const locale = this.getLocale();
7099
+ return locale.split("-")[0];
7100
+ };
7560
7101
  }
7561
7102
  // Generate deterministic instance ID based on current page URL
7562
7103
  _generateDeterministicInstanceId() {
@@ -7593,21 +7134,14 @@ var VenusAPI2 = class {
7593
7134
  // BOOTSTRAP METHODS
7594
7135
  //---------------------------------------
7595
7136
  _detectHostedEnvironment() {
7596
- console.log("[Venus SDK] Detecting host environment...");
7597
7137
  const isInIframe = window.self !== window.top;
7598
7138
  const hasReactNativeWebView = typeof window.ReactNativeWebView !== "undefined";
7599
7139
  this._bootstrap.isInsideHostedEnvironment = isInIframe || hasReactNativeWebView;
7600
- console.log(
7601
- `[Venus SDK] isInIframe: ${isInIframe}, hasReactNativeWebView: ${hasReactNativeWebView}`
7602
- );
7603
- }
7604
- isMobile() {
7605
- return typeof window.ReactNativeWebView !== "undefined";
7606
7140
  }
7607
7141
  _initializeMockMode() {
7608
7142
  if (this._mock.localeOverride) {
7609
- this.config.locale = this._mock.localeOverride;
7610
- this.config.languageCode = this._mock.localeOverride.split("-")[0];
7143
+ this._localeData = this._mock.localeOverride;
7144
+ this._languageCodeData = this._mock.localeOverride.split("-")[0];
7611
7145
  }
7612
7146
  if (this._mock.roomsData) {
7613
7147
  console.warn(
@@ -7627,6 +7161,10 @@ var VenusAPI2 = class {
7627
7161
  }
7628
7162
  this._shared.initPromise = new Promise(async (resolve, reject) => {
7629
7163
  try {
7164
+ if (this.isMock() && options?.mock) {
7165
+ Object.assign(this._mock, options.mock);
7166
+ console.log("[VenusAPI] Mock options applied:", options.mock);
7167
+ }
7630
7168
  const result = await this.host.initialize(options);
7631
7169
  this._shared.initialized = true;
7632
7170
  if (!options || !options.usePreloader) {
@@ -7654,7 +7192,6 @@ instance.isAvailable = function() {
7654
7192
  (async () => {
7655
7193
  try {
7656
7194
  await initializeNumbers(instance);
7657
- console.log("[Venus SDK] Numbers system initialized");
7658
7195
  } catch (error) {
7659
7196
  console.error("[Venus SDK] Failed to initialize numbers system:", error);
7660
7197
  }