@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
package/dist/index.cjs CHANGED
@@ -1,243 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
4
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- };
11
- var __export = (target, all) => {
12
- for (var name in all)
13
- __defProp(target, name, { get: all[name], enumerable: true });
14
- };
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
5
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
25
6
 
26
- // src/rooms/RoomsApi.ts
27
- var init_RoomsApi = __esm({
28
- "src/rooms/RoomsApi.ts"() {
29
- }
30
- });
31
-
32
- // src/rooms/VenusRoom.ts
33
- exports.VenusRoom = void 0;
34
- var init_VenusRoom = __esm({
35
- "src/rooms/VenusRoom.ts"() {
36
- exports.VenusRoom = class {
37
- constructor(roomData) {
38
- __publicField(this, "id");
39
- __publicField(this, "name");
40
- __publicField(this, "players");
41
- __publicField(this, "maxPlayers");
42
- __publicField(this, "gameType");
43
- __publicField(this, "appId");
44
- __publicField(this, "type");
45
- __publicField(this, "createdBy");
46
- __publicField(this, "createdAt");
47
- __publicField(this, "updatedAt");
48
- __publicField(this, "isPrivate");
49
- __publicField(this, "currentPlayers");
50
- __publicField(this, "status");
51
- __publicField(this, "customMetadata");
52
- __publicField(this, "admins");
53
- __publicField(this, "roomCode");
54
- __publicField(this, "description");
55
- __publicField(this, "data");
56
- __publicField(this, "version");
57
- __publicField(this, "_subscriptions", /* @__PURE__ */ new Map());
58
- this.id = roomData.id;
59
- this.name = roomData.name;
60
- this.players = roomData.currentPlayers || [];
61
- this.maxPlayers = roomData.maxPlayers;
62
- this.gameType = roomData.gameType;
63
- this.appId = roomData.appId;
64
- this.type = roomData.type;
65
- this.createdBy = roomData.createdBy;
66
- this.createdAt = roomData.createdAt;
67
- this.updatedAt = roomData.updatedAt;
68
- this.isPrivate = roomData.isPrivate;
69
- this.currentPlayers = roomData.currentPlayers || [];
70
- this.status = roomData.status;
71
- this.customMetadata = roomData.customMetadata || {};
72
- this.admins = roomData.admins || [];
73
- this.roomCode = roomData.roomCode;
74
- this.description = roomData.description;
75
- this.data = roomData.data || {};
76
- this.version = roomData.version;
77
- console.log(`VenusRoom: Created room object for ${this.id}`, {
78
- hasCustomMetadata: !!this.customMetadata,
79
- hasGameState: !!this.customMetadata?.rules?.gameState,
80
- gamePhase: this.customMetadata?.rules?.gameState?.phase,
81
- currentPlayer: this.customMetadata?.rules?.gameState?.currentPlayer
82
- });
83
- }
84
- updateFromRoomData(newRoomData) {
85
- if (newRoomData.id === this.id) {
86
- this.name = newRoomData.name || this.name;
87
- this.players = newRoomData.currentPlayers || this.players;
88
- this.maxPlayers = newRoomData.maxPlayers || this.maxPlayers;
89
- this.gameType = newRoomData.gameType || this.gameType;
90
- this.currentPlayers = newRoomData.currentPlayers || this.currentPlayers;
91
- this.customMetadata = newRoomData.customMetadata || this.customMetadata;
92
- this.data = newRoomData.data || this.data;
93
- this.status = newRoomData.status || this.status;
94
- this.updatedAt = newRoomData.updatedAt || this.updatedAt;
95
- console.log(`VenusRoom: Updated room object ${this.id} with fresh data`, {
96
- hasCustomMetadata: !!this.customMetadata,
97
- hasGameState: !!this.customMetadata?.rules?.gameState,
98
- gamePhase: this.customMetadata?.rules?.gameState?.phase,
99
- currentPlayer: this.customMetadata?.rules?.gameState?.currentPlayer
100
- });
101
- }
102
- }
103
- };
104
- }
105
- });
106
-
107
- // src/rooms/index.ts
108
- var rooms_exports = {};
109
- __export(rooms_exports, {
110
- VenusRoom: () => exports.VenusRoom,
111
- initializeRoomsApi: () => initializeRoomsApi,
112
- setupRoomNotifications: () => setupRoomNotifications
113
- });
114
- function bindMethod(target, targetKey, source, sourceKey) {
115
- const key = sourceKey ?? targetKey;
116
- const fn = source?.[key];
117
- if (typeof fn === "function") {
118
- target[targetKey] = fn.bind(source);
119
- return true;
120
- }
121
- return false;
122
- }
123
- function setupRoomNotifications(transport, getSubscriptions) {
124
- console.log("[Venus Rooms] Setting up room notification listeners");
125
- return transport.onVenusMessage((message) => {
126
- const subscriptions = getSubscriptions();
127
- if (!subscriptions) {
128
- return;
129
- }
130
- if (message.type === "H5_ROOM_DATA_UPDATED") {
131
- const messageData = message.data;
132
- const { roomId, roomData } = messageData;
133
- if (!roomId) return;
134
- const callbacks = subscriptions.data?.[roomId] || [];
135
- const allEventsCallbacks = subscriptions.allEvents?.[roomId] || [];
136
- console.log(`[Venus Rooms] \u{1F514} Room data updated for ${roomId}, notifying ${callbacks.length} callbacks`, roomData);
137
- callbacks.forEach((callback) => {
138
- try {
139
- callback(roomData);
140
- } catch (error) {
141
- console.error("[Venus Rooms] Error in room data callback:", error);
142
- throw error;
143
- }
144
- });
145
- allEventsCallbacks.forEach((callback) => {
146
- try {
147
- callback({ type: message.type, ...messageData });
148
- } catch (error) {
149
- console.error("[Venus Rooms] Error in allEvents callback:", error);
150
- throw error;
151
- }
152
- });
153
- }
154
- if (message.type === "H5_ROOM_MESSAGE_RECEIVED" || message.type === "H5_ROOM_MESSAGE_UPDATED" || message.type === "H5_ROOM_MESSAGE_DELETED") {
155
- const messageData = message.data;
156
- const { roomId } = messageData;
157
- if (!roomId) return;
158
- const callbacks = subscriptions.messages?.[roomId] || [];
159
- const allEventsCallbacks = subscriptions.allEvents?.[roomId] || [];
160
- console.log(`[Venus Rooms] \u{1F514} Room message event for ${roomId}, notifying ${callbacks.length} callbacks`);
161
- callbacks.forEach((callback) => {
162
- try {
163
- callback(messageData);
164
- } catch (error) {
165
- console.error("[Venus Rooms] Error in room message callback:", error);
166
- throw error;
167
- }
168
- });
169
- allEventsCallbacks.forEach((callback) => {
170
- try {
171
- callback({ type: message.type, ...messageData });
172
- } catch (error) {
173
- console.error("[Venus Rooms] Error in allEvents callback:", error);
174
- throw error;
175
- }
176
- });
177
- }
178
- if (message.type === "app:h5:proposedMoveValidationUpdated") {
179
- const messageData = message.data;
180
- const { roomId } = messageData;
181
- if (!roomId) return;
182
- const callbacks = subscriptions.gameEvents?.[roomId] || [];
183
- const allEventsCallbacks = subscriptions.allEvents?.[roomId] || [];
184
- console.log(`[Venus Rooms] \u{1F514} Proposed move validation updated for ${roomId}, notifying ${callbacks.length} callbacks`);
185
- callbacks.forEach((callback) => {
186
- try {
187
- callback(messageData);
188
- } catch (error) {
189
- console.error("[Venus Rooms] Error in game event callback:", error);
190
- throw error;
191
- }
192
- });
193
- allEventsCallbacks.forEach((callback) => {
194
- try {
195
- callback({ type: message.type, ...messageData });
196
- } catch (error) {
197
- console.error("[Venus Rooms] Error in allEvents callback:", error);
198
- throw error;
199
- }
200
- });
201
- }
202
- });
203
- }
204
- function initializeRoomsApi(venusApi, host) {
205
- const roomsApi = host?.rooms;
206
- if (!roomsApi) {
207
- console.warn(
208
- "[Venus SDK] Host did not provide a rooms implementation. Rooms API will be unavailable."
209
- );
210
- return;
211
- }
212
- const venus = venusApi;
213
- const existingNamespace = venus.rooms || {};
214
- const roomsNamespace = Object.assign({}, existingNamespace);
215
- const namespaceBindings = [
216
- ["create", "createRoom"],
217
- ["joinOrCreate", "joinOrCreateRoom"],
218
- ["joinByCode", "joinRoomByCode"],
219
- ["list", "getUserRooms"],
220
- ["subscribeToRoom", "subscribe"],
221
- ["updateRoomData", "updateData"],
222
- ["getRoomData", "getData"],
223
- ["sendRoomMessage", "sendMessage"],
224
- ["leaveRoom", "leave"],
225
- ["startRoomGame", "startGame"],
226
- ["proposeMove"],
227
- ["validateMove"]
228
- ];
229
- namespaceBindings.forEach(([targetKey, sourceKey]) => {
230
- bindMethod(roomsNamespace, targetKey, roomsApi, sourceKey);
231
- });
232
- venus.rooms = roomsNamespace;
233
- }
234
- var init_rooms = __esm({
235
- "src/rooms/index.ts"() {
236
- init_RoomsApi();
237
- init_VenusRoom();
238
- }
239
- });
240
-
241
7
  // src/VenusMessageId.ts
242
8
  var VenusMessageId = /* @__PURE__ */ ((VenusMessageId2) => {
243
9
  VenusMessageId2["H5_RESPONSE"] = "H5_RESPONSE";
@@ -284,10 +50,6 @@ var VenusMessageId = /* @__PURE__ */ ((VenusMessageId2) => {
284
50
  VenusMessageId2["CONFIRM_DIALOG"] = "H5_CONFIRM_DIALOG";
285
51
  VenusMessageId2["ACTION_SHEET_SHOW"] = "H5_ACTION_SHEET_SHOW";
286
52
  VenusMessageId2["REQUEST_SERVER_TIME"] = "H5_REQUEST_SERVER_TIME";
287
- VenusMessageId2["GET_POST_INTERACTIONS"] = "H5_GET_POST_INTERACTIONS";
288
- VenusMessageId2["TOGGLE_LIKE"] = "H5_TOGGLE_LIKE";
289
- VenusMessageId2["OPEN_COMMENTS"] = "H5_OPEN_COMMENTS";
290
- VenusMessageId2["TOGGLE_FOLLOW"] = "H5_TOGGLE_FOLLOW";
291
53
  VenusMessageId2["SHARE_LINK"] = "H5_SHARE_LINK";
292
54
  VenusMessageId2["CREATE_SHARE_QRCODE"] = "H5_CREATE_SHARE_QRCODE";
293
55
  VenusMessageId2["AI_CHAT_COMPLETION"] = "H5_AI_CHAT_COMPLETION";
@@ -329,11 +91,14 @@ var VenusMessageId = /* @__PURE__ */ ((VenusMessageId2) => {
329
91
  VenusMessageId2["H5_SIMULATION_GET_AVAILABLE_ITEMS"] = "H5_SIMULATION_GET_AVAILABLE_ITEMS";
330
92
  VenusMessageId2["H5_SIMULATION_VALIDATE_ASSIGNMENT"] = "H5_SIMULATION_VALIDATE_ASSIGNMENT";
331
93
  VenusMessageId2["H5_SIMULATION_BATCH_OPERATIONS"] = "H5_SIMULATION_BATCH_OPERATIONS";
332
- VenusMessageId2["H5_LEADERBOARD_START_RUN"] = "H5_LEADERBOARD_START_RUN";
94
+ VenusMessageId2["H5_SIMULATION_SUBSCRIBE"] = "H5_SIMULATION_SUBSCRIBE";
95
+ VenusMessageId2["H5_SIMULATION_UNSUBSCRIBE"] = "H5_SIMULATION_UNSUBSCRIBE";
96
+ VenusMessageId2["H5_SIMULATION_UPDATE"] = "H5_SIMULATION_UPDATE";
97
+ VenusMessageId2["H5_LEADERBOARD_CREATE_SCORE_TOKEN"] = "H5_LEADERBOARD_CREATE_SCORE_TOKEN";
333
98
  VenusMessageId2["H5_LEADERBOARD_SUBMIT_SCORE"] = "H5_LEADERBOARD_SUBMIT_SCORE";
334
- VenusMessageId2["H5_LEADERBOARD_GET"] = "H5_LEADERBOARD_GET";
335
- VenusMessageId2["H5_LEADERBOARD_GET_HIGHLIGHT"] = "H5_LEADERBOARD_GET_HIGHLIGHT";
336
- VenusMessageId2["H5_LEADERBOARD_GET_PLAYER_STATS"] = "H5_LEADERBOARD_GET_PLAYER_STATS";
99
+ VenusMessageId2["H5_LEADERBOARD_GET_PAGED_SCORES"] = "H5_LEADERBOARD_GET_PAGED_SCORES";
100
+ VenusMessageId2["H5_LEADERBOARD_GET_PODIUM_SCORES"] = "H5_LEADERBOARD_GET_PODIUM_SCORES";
101
+ VenusMessageId2["H5_LEADERBOARD_GET_MY_RANK"] = "H5_LEADERBOARD_GET_MY_RANK";
337
102
  VenusMessageId2["H5_ROOM_CREATE"] = "H5_ROOM_CREATE";
338
103
  VenusMessageId2["H5_ROOM_JOIN"] = "H5_ROOM_JOIN";
339
104
  VenusMessageId2["H5_ROOM_JOIN_OR_CREATE"] = "H5_ROOM_JOIN_OR_CREATE";
@@ -588,7 +353,7 @@ var MockAvatarApi = class {
588
353
  async deleteAvatar() {
589
354
  console.log(`[Venus Mock] Deleting avatar3d config`);
590
355
  const venusApi = this._venusApi;
591
- const currentProfile = venusApi.getCurrentProfile();
356
+ const currentProfile = venusApi.getProfile();
592
357
  const profileId = currentProfile?.id || "default_profile";
593
358
  localStorage.removeItem(`venus-mock-avatar3d-${profileId}`);
594
359
  console.log(
@@ -603,7 +368,7 @@ var MockAvatarApi = class {
603
368
  console.log(`[Venus Mock] Loading shared avatar3d by ID: ${avatar3dId}`);
604
369
  config = await this.selectAvatarConfig(avatar3dId, false);
605
370
  } else {
606
- const currentProfile = venusApi.getCurrentProfile();
371
+ const currentProfile = venusApi.getProfile();
607
372
  const profileId = currentProfile?.id || "default_profile";
608
373
  console.log(`[Venus Mock] Loading avatar3d for profile: ${profileId}`);
609
374
  console.log(
@@ -620,7 +385,7 @@ var MockAvatarApi = class {
620
385
  async saveAvatar(config) {
621
386
  console.log(`[Venus Mock] Saving avatar3d config:`, config);
622
387
  const venusApi = this._venusApi;
623
- const currentProfile = venusApi.getCurrentProfile();
388
+ const currentProfile = venusApi.getProfile();
624
389
  const profileId = currentProfile?.id || "default_profile";
625
390
  localStorage.setItem(
626
391
  `venus-mock-avatar3d-${profileId}`,
@@ -1136,7 +901,8 @@ var HostCdnApi = class {
1136
901
  return index === pathParts.length - 1 ? encodeURIComponent(part) : part;
1137
902
  });
1138
903
  const encodedSubPath = encodedParts.join("/");
1139
- const fullUrl = this.baseUrl + "/" + encodedSubPath;
904
+ const cacheBust = Date.now();
905
+ const fullUrl = this.baseUrl + "/" + encodedSubPath + `?cacheBust=${cacheBust}`;
1140
906
  return fullUrl;
1141
907
  }
1142
908
  resolveAvatarAssetUrl(subPath) {
@@ -1151,9 +917,15 @@ var HostCdnApi = class {
1151
917
 
1152
918
  // src/cdn/MockCdnApi.ts
1153
919
  var MockCdnApi = class {
1154
- constructor() {
1155
- __publicField(this, "baseUrl");
1156
- this.baseUrl = "https://venus-static-01293ak.web.app/";
920
+ constructor(venusApi) {
921
+ __publicField(this, "venusApi");
922
+ this.venusApi = venusApi;
923
+ }
924
+ get baseUrl() {
925
+ return this.venusApi._mock?.cdnBaseUrl ?? "https://venus-static-01293ak.web.app/";
926
+ }
927
+ get forceRemoteCdn() {
928
+ return this.venusApi._mock?.cdnForceRemote ?? false;
1157
929
  }
1158
930
  async fetchBlob(path, options) {
1159
931
  const controller = new AbortController();
@@ -1190,6 +962,10 @@ var MockCdnApi = class {
1190
962
  return subPath;
1191
963
  }
1192
964
  const cleanSubPath = subPath.startsWith("/") ? subPath.slice(1) : subPath;
965
+ const isLocalhost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
966
+ if (isLocalhost && !this.forceRemoteCdn) {
967
+ return `/${cleanSubPath}`;
968
+ }
1193
969
  const pathParts = cleanSubPath.split("/");
1194
970
  const encodedParts = pathParts.map((part, index) => {
1195
971
  return index === pathParts.length - 1 ? encodeURIComponent(part) : part;
@@ -1311,6 +1087,212 @@ function initializeCdn(venusApi, host) {
1311
1087
  venusApi.cdn = host.cdn;
1312
1088
  }
1313
1089
 
1090
+ // src/device/HostDeviceApi.ts
1091
+ var HostDeviceApi = class {
1092
+ constructor(venusApi) {
1093
+ __publicField(this, "venusApi");
1094
+ this.venusApi = venusApi;
1095
+ }
1096
+ getDevice() {
1097
+ const device = this.venusApi._deviceData;
1098
+ if (!device) {
1099
+ throw new Error(
1100
+ "[Venus SDK] Device info not available. You must await VenusAPI.initializeAsync() before calling getDevice(). INIT_SDK has not completed."
1101
+ );
1102
+ }
1103
+ return device;
1104
+ }
1105
+ };
1106
+
1107
+ // src/device/MockDeviceApi.ts
1108
+ var MockDeviceApi = class {
1109
+ constructor(venusApi) {
1110
+ __publicField(this, "venusApi");
1111
+ this.venusApi = venusApi;
1112
+ }
1113
+ getDevice() {
1114
+ const width = typeof window !== "undefined" ? window.innerWidth : 400;
1115
+ const height = typeof window !== "undefined" ? window.innerHeight : 800;
1116
+ return {
1117
+ screenSize: { width, height },
1118
+ viewportSize: {
1119
+ width: width - 20,
1120
+ // account for safe area
1121
+ height: height - 20
1122
+ },
1123
+ orientation: width > height ? "landscape" : "portrait",
1124
+ pixelRatio: typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1,
1125
+ fontScale: 1,
1126
+ deviceType: width > 768 ? "tablet" : "phone",
1127
+ hapticsEnabled: false,
1128
+ haptics: { supported: false, enabled: false }
1129
+ };
1130
+ }
1131
+ };
1132
+
1133
+ // src/environment/HostEnvironmentApi.ts
1134
+ var HostEnvironmentApi = class {
1135
+ constructor(venusApi) {
1136
+ __publicField(this, "venusApi");
1137
+ this.venusApi = venusApi;
1138
+ }
1139
+ getEnvironment() {
1140
+ const environment = this.venusApi._environmentData;
1141
+ if (!environment) {
1142
+ throw new Error(
1143
+ "[Venus SDK] Environment info not available. You must await VenusAPI.initializeAsync() before calling getEnvironment(). INIT_SDK has not completed."
1144
+ );
1145
+ }
1146
+ return environment;
1147
+ }
1148
+ };
1149
+
1150
+ // src/environment/MockEnvironmentApi.ts
1151
+ var MockEnvironmentApi = class {
1152
+ constructor(venusApi) {
1153
+ __publicField(this, "venusApi");
1154
+ this.venusApi = venusApi;
1155
+ }
1156
+ getEnvironment() {
1157
+ const getBrowser = () => {
1158
+ if (typeof navigator === "undefined") return "unknown";
1159
+ const userAgent = navigator.userAgent;
1160
+ if (/chrome|chromium|crios/i.test(userAgent)) return "chrome";
1161
+ if (/firefox|fxios/i.test(userAgent)) return "firefox";
1162
+ if (/safari/i.test(userAgent)) return "safari";
1163
+ if (/edg/i.test(userAgent)) return "edge";
1164
+ if (/opera|opr/i.test(userAgent)) return "opera";
1165
+ return "unknown";
1166
+ };
1167
+ return {
1168
+ isDevelopment: true,
1169
+ platform: "web",
1170
+ platformVersion: "mock-1.0",
1171
+ browserInfo: {
1172
+ browser: getBrowser(),
1173
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "mock-agent",
1174
+ isMobile: typeof navigator !== "undefined" ? /Mobi|Android/i.test(navigator.userAgent) : false,
1175
+ isTablet: typeof navigator !== "undefined" ? /iPad|Tablet|Pad/i.test(navigator.userAgent) : false,
1176
+ language: typeof navigator !== "undefined" ? navigator.language || "en-US" : "en-US"
1177
+ }
1178
+ };
1179
+ }
1180
+ };
1181
+
1182
+ // src/system/HostSystemApi.ts
1183
+ var HostSystemApi = class {
1184
+ constructor(deviceApi, environmentApi, venusApi) {
1185
+ __publicField(this, "deviceApi");
1186
+ __publicField(this, "environmentApi");
1187
+ __publicField(this, "venusApi");
1188
+ this.deviceApi = deviceApi;
1189
+ this.environmentApi = environmentApi;
1190
+ this.venusApi = venusApi;
1191
+ }
1192
+ getDevice() {
1193
+ return this.deviceApi.getDevice();
1194
+ }
1195
+ getEnvironment() {
1196
+ return this.environmentApi.getEnvironment();
1197
+ }
1198
+ getSafeArea() {
1199
+ const safeArea = this.venusApi._safeAreaData;
1200
+ if (!safeArea) {
1201
+ throw new Error(
1202
+ "[Venus SDK] getSafeArea() called before initialization. Call VenusAPI.initializeAsync() first."
1203
+ );
1204
+ }
1205
+ return { ...safeArea };
1206
+ }
1207
+ isMobile() {
1208
+ const environment = this.environmentApi.getEnvironment();
1209
+ if (environment.platform === "ios" || environment.platform === "android") {
1210
+ return true;
1211
+ }
1212
+ if (environment.browserInfo) {
1213
+ return environment.browserInfo.isMobile;
1214
+ }
1215
+ return true;
1216
+ }
1217
+ isWeb() {
1218
+ const environment = this.environmentApi.getEnvironment();
1219
+ if (environment.platform === "web") {
1220
+ return true;
1221
+ }
1222
+ if (environment.browserInfo && !environment.browserInfo.isMobile) {
1223
+ return true;
1224
+ }
1225
+ return false;
1226
+ }
1227
+ };
1228
+
1229
+ // src/system/MockSystemApi.ts
1230
+ var MockSystemApi = class {
1231
+ constructor(deviceApi, environmentApi, venusApi) {
1232
+ __publicField(this, "deviceApi");
1233
+ __publicField(this, "environmentApi");
1234
+ __publicField(this, "venusApi");
1235
+ this.deviceApi = deviceApi;
1236
+ this.environmentApi = environmentApi;
1237
+ this.venusApi = venusApi;
1238
+ }
1239
+ getDevice() {
1240
+ return this.deviceApi.getDevice();
1241
+ }
1242
+ getEnvironment() {
1243
+ return this.environmentApi.getEnvironment();
1244
+ }
1245
+ getSafeArea() {
1246
+ const safeArea = this.venusApi._safeAreaData;
1247
+ if (!safeArea) {
1248
+ return {
1249
+ top: 0,
1250
+ right: 0,
1251
+ bottom: 34,
1252
+ left: 0
1253
+ };
1254
+ }
1255
+ return { ...safeArea };
1256
+ }
1257
+ isMobile() {
1258
+ const environment = this.environmentApi.getEnvironment();
1259
+ if (environment.platform === "ios" || environment.platform === "android") {
1260
+ return true;
1261
+ }
1262
+ if (environment.browserInfo) {
1263
+ return environment.browserInfo.isMobile;
1264
+ }
1265
+ return true;
1266
+ }
1267
+ isWeb() {
1268
+ const environment = this.environmentApi.getEnvironment();
1269
+ if (environment.platform === "web") {
1270
+ return true;
1271
+ }
1272
+ if (environment.browserInfo && !environment.browserInfo.isMobile) {
1273
+ return true;
1274
+ }
1275
+ return false;
1276
+ }
1277
+ };
1278
+
1279
+ // src/system/index.ts
1280
+ function initializeSystem(venusApi, host) {
1281
+ venusApi.system = host.system;
1282
+ venusApi.isMobile = () => {
1283
+ console.warn(
1284
+ "[Venus SDK] DEPRECATED: VenusAPI.isMobile() is deprecated. Use VenusAPI.system.isMobile() instead."
1285
+ );
1286
+ return host.system.isMobile();
1287
+ };
1288
+ venusApi.isWeb = () => {
1289
+ console.warn(
1290
+ "[Venus SDK] DEPRECATED: VenusAPI.isWeb() is deprecated. Use VenusAPI.system.isWeb() instead."
1291
+ );
1292
+ return host.system.isWeb();
1293
+ };
1294
+ }
1295
+
1314
1296
  // src/features/RpcFeaturesApi.ts
1315
1297
  var RpcFeaturesApi = class {
1316
1298
  constructor(rcpClient) {
@@ -1793,13 +1775,8 @@ var MockNotificationsApi = class {
1793
1775
  async cancelNotification(notificationId) {
1794
1776
  const venusApi = this.venusApi;
1795
1777
  if (isWebPlatform()) {
1796
- console.log(
1797
- "[Venus Mock] Cancel notification on web platform (simulated):",
1798
- notificationId
1799
- );
1800
1778
  return true;
1801
1779
  }
1802
- console.log("[Venus Mock] Cancel local notification:", notificationId);
1803
1780
  await createMockDelay(MOCK_DELAYS.short);
1804
1781
  if (venusApi._mock.scheduledNotifications && venusApi._mock.scheduledNotifications[notificationId]) {
1805
1782
  delete venusApi._mock.scheduledNotifications[notificationId];
@@ -1809,12 +1786,8 @@ var MockNotificationsApi = class {
1809
1786
  }
1810
1787
  async getAllScheduledLocalNotifications() {
1811
1788
  if (isWebPlatform()) {
1812
- console.log(
1813
- "[Venus Mock] Get notifications on web platform (returning empty list)"
1814
- );
1815
1789
  return [];
1816
1790
  }
1817
- console.log("[Venus Mock] Get all scheduled local notifications");
1818
1791
  await createMockDelay(MOCK_DELAYS.short);
1819
1792
  const venusApi = this.venusApi;
1820
1793
  const notifications = venusApi._mock.scheduledNotifications || {};
@@ -1822,10 +1795,8 @@ var MockNotificationsApi = class {
1822
1795
  }
1823
1796
  async isLocalNotificationsEnabled() {
1824
1797
  if (isWebPlatform()) {
1825
- console.log("[Venus Mock] Notifications not available on web platform");
1826
1798
  return false;
1827
1799
  }
1828
- console.log("[Venus Mock] Check if local notifications are enabled");
1829
1800
  await createMockDelay(MOCK_DELAYS.short);
1830
1801
  const venusApi = this.venusApi;
1831
1802
  const isEnabled = venusApi._mock.notificationsEnabled !== false;
@@ -1834,9 +1805,6 @@ var MockNotificationsApi = class {
1834
1805
  async scheduleAsync(title, body, seconds, notificationId, options) {
1835
1806
  const { priority = 50, groupId, payload } = options || {};
1836
1807
  if (isWebPlatform()) {
1837
- console.log(
1838
- "[Venus Mock] Notifications not supported on web platform, simulating success"
1839
- );
1840
1808
  console.info(
1841
1809
  "\u{1F514} [Venus Mock] Notification would be scheduled:",
1842
1810
  title || "Untitled",
@@ -1847,14 +1815,11 @@ var MockNotificationsApi = class {
1847
1815
  const mockId = `mock-web-notification-${Date.now()}`;
1848
1816
  return mockId;
1849
1817
  }
1850
- console.log("[Venus Mock] Schedule local notification:", { title, body, seconds, options });
1851
1818
  const venusApi = this.venusApi;
1852
1819
  if (!venusApi._mock.pendingRequests) {
1853
- console.log("[Venus Mock] Initializing pendingRequests");
1854
1820
  venusApi._mock.pendingRequests = {};
1855
1821
  }
1856
1822
  const requestId = Date.now().toString();
1857
- console.log("[Venus Mock] Creating request with ID:", requestId);
1858
1823
  return new Promise((resolve) => {
1859
1824
  venusApi._mock.pendingRequests[requestId] = { resolve };
1860
1825
  const id = notificationId || `mock-notification-${Date.now()}`;
@@ -1876,13 +1841,8 @@ var MockNotificationsApi = class {
1876
1841
  async setLocalNotificationsEnabled(enabled) {
1877
1842
  const venusApi = this.venusApi;
1878
1843
  if (isWebPlatform()) {
1879
- console.log(
1880
- "[Venus Mock] Set notifications enabled on web platform (simulated):",
1881
- enabled
1882
- );
1883
1844
  return true;
1884
1845
  }
1885
- console.log("[Venus Mock] Set local notifications enabled:", enabled);
1886
1846
  await createMockDelay(MOCK_DELAYS.short);
1887
1847
  venusApi._mock.notificationsEnabled = enabled;
1888
1848
  return enabled;
@@ -2107,16 +2067,20 @@ function initializePopups(venusApi, host) {
2107
2067
 
2108
2068
  // src/profile/HostProfileApi.ts
2109
2069
  var HostProfileApi = class {
2070
+ constructor(venusApi) {
2071
+ __publicField(this, "venusApi");
2072
+ this.venusApi = venusApi;
2073
+ }
2110
2074
  getCurrentProfile() {
2111
- const profile = window.venus?.profile;
2075
+ const profile = this.venusApi._profileData;
2112
2076
  if (!profile) {
2113
2077
  throw new Error(
2114
- "[Venus SDK] Host profile handshake did not complete. Await VenusAPI.initializeAsync() so INIT_SDK can deliver the profile before calling profile APIs."
2078
+ "[Venus SDK] Profile not available. You must await VenusAPI.initializeAsync() before calling getProfile(). INIT_SDK has not completed."
2115
2079
  );
2116
2080
  }
2117
2081
  if (!profile.id || !profile.username) {
2118
2082
  throw new Error(
2119
- "[Venus SDK] INIT_SDK returned an incomplete profile (missing id/username). The host must supply real credentials before rooms APIs are used."
2083
+ "[Venus SDK] INIT_SDK returned an incomplete profile (missing id/username). The host must supply valid profile data."
2120
2084
  );
2121
2085
  }
2122
2086
  return {
@@ -2130,6 +2094,10 @@ var HostProfileApi = class {
2130
2094
 
2131
2095
  // src/profile/MockProfileApi.ts
2132
2096
  var MockProfileApi = class {
2097
+ constructor(venusApi) {
2098
+ __publicField(this, "venusApi");
2099
+ this.venusApi = venusApi;
2100
+ }
2133
2101
  getCurrentProfile() {
2134
2102
  return {
2135
2103
  id: "mock_profile_123",
@@ -2142,11 +2110,22 @@ var MockProfileApi = class {
2142
2110
 
2143
2111
  // src/profile/index.ts
2144
2112
  function initializeProfile(venusApi, host) {
2113
+ venusApi.getProfile = () => {
2114
+ return host.profile.getCurrentProfile();
2115
+ };
2145
2116
  venusApi.getCurrentProfile = () => {
2117
+ console.warn(
2118
+ "[Venus SDK] DEPRECATED: VenusAPI.getCurrentProfile() is deprecated. Use VenusAPI.getProfile() instead. See migration guide: https://docs.venus.com/migration/profile-api"
2119
+ );
2146
2120
  return host.profile.getCurrentProfile();
2147
2121
  };
2148
2122
  }
2149
2123
 
2124
+ // src/utils/idGenerator.ts
2125
+ function generateId() {
2126
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
2127
+ }
2128
+
2150
2129
  // src/rpc/RpcClient.ts
2151
2130
  var RpcClient = class {
2152
2131
  constructor() {
@@ -2189,7 +2168,7 @@ var RpcClient = class {
2189
2168
  }
2190
2169
  async call(method, args, timeout = 5e3) {
2191
2170
  return new Promise((resolve, reject) => {
2192
- const id = this.generateId();
2171
+ const id = generateId();
2193
2172
  this.addPendingCall(id, resolve, reject);
2194
2173
  const request = {
2195
2174
  type: "rpc-request",
@@ -2226,9 +2205,6 @@ var RpcClient = class {
2226
2205
  getPendingCall(id) {
2227
2206
  return this.pendingCalls.get(id);
2228
2207
  }
2229
- generateId() {
2230
- return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
2231
- }
2232
2208
  handleRpcResponse(response) {
2233
2209
  const pending = this.getPendingCall(response.id);
2234
2210
  if (!pending) {
@@ -2250,45 +2226,462 @@ var RpcClient = class {
2250
2226
  }
2251
2227
  };
2252
2228
 
2253
- // src/index.ts
2254
- init_rooms();
2255
-
2256
- // src/storage/MockStorageApi.ts
2257
- function createMockStorageApi(storageType, appUrl) {
2258
- const appIdentifier = appUrl ? generateAppIdentifier(appUrl) : null;
2259
- let prefix;
2260
- let syncDelay = 0;
2261
- switch (storageType) {
2262
- case "deviceCache":
2263
- prefix = "venus:app";
2264
- syncDelay = 0;
2265
- break;
2266
- case "appStorage":
2267
- prefix = "venus:app";
2268
- syncDelay = 100;
2269
- break;
2270
- case "globalStorage":
2271
- prefix = "venus:global";
2272
- syncDelay = 100;
2273
- break;
2274
- default:
2275
- throw new Error(`Unknown storage type: ${storageType}`);
2229
+ // src/rooms/VenusRoom.ts
2230
+ var VenusRoom = class {
2231
+ constructor(roomData) {
2232
+ __publicField(this, "id");
2233
+ __publicField(this, "name");
2234
+ __publicField(this, "players");
2235
+ __publicField(this, "maxPlayers");
2236
+ __publicField(this, "gameType");
2237
+ __publicField(this, "appId");
2238
+ __publicField(this, "type");
2239
+ __publicField(this, "createdBy");
2240
+ __publicField(this, "createdAt");
2241
+ __publicField(this, "updatedAt");
2242
+ __publicField(this, "isPrivate");
2243
+ __publicField(this, "status");
2244
+ __publicField(this, "customMetadata");
2245
+ __publicField(this, "admins");
2246
+ __publicField(this, "roomCode");
2247
+ __publicField(this, "description");
2248
+ __publicField(this, "data");
2249
+ __publicField(this, "version");
2250
+ this.id = roomData.id;
2251
+ this.name = roomData.name;
2252
+ this.players = Array.isArray(roomData.currentPlayers) ? [...roomData.currentPlayers] : [];
2253
+ this.maxPlayers = roomData.maxPlayers;
2254
+ this.gameType = roomData.gameType;
2255
+ this.appId = roomData.appId;
2256
+ this.type = roomData.type;
2257
+ this.createdBy = roomData.createdBy;
2258
+ this.createdAt = roomData.createdAt;
2259
+ this.updatedAt = roomData.updatedAt;
2260
+ this.isPrivate = roomData.isPrivate;
2261
+ this.status = roomData.status;
2262
+ this.customMetadata = roomData.customMetadata || {};
2263
+ this.admins = Array.isArray(roomData.admins) ? [...roomData.admins] : [];
2264
+ this.roomCode = roomData.roomCode;
2265
+ this.description = roomData.description;
2266
+ this.data = roomData.data || {};
2267
+ this.version = roomData.version;
2276
2268
  }
2277
- prefix = storageType === "globalStorage" || !appIdentifier ? `${prefix}:` : `${prefix}:${appIdentifier}:`;
2278
- return new MockStorageApi(prefix, syncDelay);
2269
+ };
2270
+
2271
+ // src/rooms/setupRoomNotifications.ts
2272
+ function invokeCallbacks(callbacks, event, context) {
2273
+ callbacks.forEach((callback) => {
2274
+ try {
2275
+ callback(event);
2276
+ } catch (error) {
2277
+ console.error(`[Venus SDK] Error in ${context} callback:`, error);
2278
+ throw error;
2279
+ }
2280
+ });
2279
2281
  }
2280
- var MockStorageApi = class {
2281
- constructor(prefix, syncDelay) {
2282
- __publicField(this, "prefix");
2283
- __publicField(this, "syncDelay");
2284
- this.prefix = prefix;
2285
- this.syncDelay = syncDelay;
2286
- }
2287
- async clear() {
2288
- const fullLength = localStorage.length;
2289
- for (let i = 0; i < fullLength; i++) {
2290
- const fullKey = localStorage.key(i);
2291
- if (fullKey && fullKey.startsWith(this.prefix)) {
2282
+ function setupRoomNotifications(transport, getSubscriptions) {
2283
+ return transport.onVenusMessage((message) => {
2284
+ const subscriptions = getSubscriptions();
2285
+ if (!subscriptions) {
2286
+ return;
2287
+ }
2288
+ if (message.type === "H5_ROOM_DATA_UPDATED") {
2289
+ const messageData = message.data;
2290
+ const { roomId, roomData } = messageData;
2291
+ if (!roomId) return;
2292
+ const callbacks = subscriptions.data[roomId] || [];
2293
+ const event = {
2294
+ type: "H5_ROOM_DATA_UPDATED",
2295
+ roomId,
2296
+ roomData,
2297
+ timestamp: messageData.timestamp
2298
+ };
2299
+ invokeCallbacks(callbacks, event, "room data");
2300
+ }
2301
+ if (message.type === "H5_ROOM_MESSAGE_RECEIVED" || message.type === "H5_ROOM_MESSAGE_UPDATED" || message.type === "H5_ROOM_MESSAGE_DELETED") {
2302
+ const messageData = message.data;
2303
+ const { roomId } = messageData;
2304
+ if (!roomId) return;
2305
+ const callbacks = subscriptions.messages[roomId] || [];
2306
+ const event = {
2307
+ type: message.type,
2308
+ roomId,
2309
+ message: messageData.message,
2310
+ timestamp: messageData.timestamp
2311
+ };
2312
+ invokeCallbacks(callbacks, event, "room message");
2313
+ }
2314
+ if (message.type === "app:h5:proposedMoveValidationUpdated") {
2315
+ const messageData = message.data;
2316
+ const { roomId } = messageData;
2317
+ if (!roomId) return;
2318
+ const callbacks = subscriptions.gameEvents[roomId] || [];
2319
+ const event = {
2320
+ type: "app:h5:proposedMoveValidationUpdated",
2321
+ roomId,
2322
+ proposedMoveData: messageData.proposedMoveData,
2323
+ proposedMoveId: messageData.proposedMoveId,
2324
+ changeType: messageData.changeType,
2325
+ timestamp: messageData.timestamp
2326
+ };
2327
+ invokeCallbacks(callbacks, event, "game event");
2328
+ }
2329
+ });
2330
+ }
2331
+
2332
+ // src/rooms/RpcRoomsApi.ts
2333
+ var RpcRoomsApi = class {
2334
+ constructor(rpcClient) {
2335
+ __publicField(this, "rpcClient");
2336
+ __publicField(this, "subscriptions");
2337
+ this.rpcClient = rpcClient;
2338
+ this.subscriptions = {
2339
+ data: {},
2340
+ messages: {},
2341
+ gameEvents: {}
2342
+ };
2343
+ }
2344
+ /**
2345
+ * Get the subscription state for external access (used by setupRoomNotifications)
2346
+ */
2347
+ getSubscriptions() {
2348
+ return this.subscriptions;
2349
+ }
2350
+ /**
2351
+ * Set up room notification routing from the transport
2352
+ */
2353
+ setupNotifications(transport) {
2354
+ setupRoomNotifications(transport, () => this.getSubscriptions());
2355
+ }
2356
+ async createRoomAsync(options) {
2357
+ const response = await this.rpcClient.call(
2358
+ "H5_ROOM_CREATE" /* H5_ROOM_CREATE */,
2359
+ {
2360
+ options
2361
+ }
2362
+ );
2363
+ if (response.success === false) {
2364
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to create room";
2365
+ throw new Error(errorMessage);
2366
+ }
2367
+ const room = new VenusRoom(response.roomData);
2368
+ return room;
2369
+ }
2370
+ async joinOrCreateRoomAsync(options) {
2371
+ const response = await this.rpcClient.call(
2372
+ "H5_ROOM_JOIN_OR_CREATE" /* H5_ROOM_JOIN_OR_CREATE */,
2373
+ {
2374
+ options
2375
+ }
2376
+ );
2377
+ if (response.success === false) {
2378
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to join or create room";
2379
+ throw new Error(errorMessage);
2380
+ }
2381
+ const room = new VenusRoom(response.value.roomData);
2382
+ return {
2383
+ action: response.value.action,
2384
+ room,
2385
+ playersJoined: response.value.playersJoined
2386
+ };
2387
+ }
2388
+ async joinRoomByCodeAsync(roomCode) {
2389
+ const response = await this.rpcClient.call(
2390
+ "H5_ROOM_JOIN_BY_CODE" /* H5_ROOM_JOIN_BY_CODE */,
2391
+ {
2392
+ roomCode
2393
+ }
2394
+ );
2395
+ if (response?.success === false) {
2396
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to join room by code";
2397
+ throw new Error(errorMessage);
2398
+ }
2399
+ const room = new VenusRoom(response.roomData);
2400
+ return room;
2401
+ }
2402
+ // Get user's rooms with optional filtering
2403
+ async getUserRoomsAsync(options = {}) {
2404
+ const response = await this.rpcClient.call(
2405
+ "H5_ROOM_GET_USER_ROOMS" /* H5_ROOM_GET_USER_ROOMS */,
2406
+ {
2407
+ includeArchived: options.includeArchived ?? false
2408
+ }
2409
+ );
2410
+ if (response?.success === false) {
2411
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to get user rooms";
2412
+ throw new Error(errorMessage);
2413
+ }
2414
+ const venusRooms = [];
2415
+ for (const roomData of response.rooms) {
2416
+ if (!roomData.id) {
2417
+ console.warn("[Venus SDK] getUserRooms: Skipping room with missing ID:", roomData);
2418
+ continue;
2419
+ }
2420
+ try {
2421
+ const venusRoom = new VenusRoom(roomData);
2422
+ venusRooms.push(venusRoom);
2423
+ } catch (error) {
2424
+ console.warn(
2425
+ "[Venus SDK] getUserRooms: Failed to create VenusRoom object:",
2426
+ error,
2427
+ roomData
2428
+ );
2429
+ }
2430
+ }
2431
+ return venusRooms;
2432
+ }
2433
+ async updateRoomDataAsync(room, updates, options = {}) {
2434
+ const response = await this.rpcClient.call(
2435
+ "H5_ROOM_UPDATE_DATA" /* H5_ROOM_UPDATE_DATA */,
2436
+ {
2437
+ roomId: room.id,
2438
+ updates,
2439
+ merge: options.merge ?? true
2440
+ }
2441
+ );
2442
+ if (response?.success === false) {
2443
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to update room data";
2444
+ throw new Error(errorMessage);
2445
+ }
2446
+ }
2447
+ async getRoomDataAsync(room) {
2448
+ const response = await this.rpcClient.call(
2449
+ "H5_ROOM_GET_DATA" /* H5_ROOM_GET_DATA */,
2450
+ {
2451
+ roomId: room.id
2452
+ }
2453
+ );
2454
+ if (response?.success === false) {
2455
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to get room data";
2456
+ throw new Error(errorMessage);
2457
+ }
2458
+ return response.data;
2459
+ }
2460
+ async sendRoomMessageAsync(venusRoom, request) {
2461
+ const response = await this.rpcClient.call(
2462
+ "H5_ROOM_SEND_MESSAGE" /* H5_ROOM_SEND_MESSAGE */,
2463
+ {
2464
+ roomId: venusRoom.id,
2465
+ message: request.message,
2466
+ metadata: request.metadata
2467
+ }
2468
+ );
2469
+ if (response?.success === false) {
2470
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to send message";
2471
+ throw new Error(errorMessage);
2472
+ }
2473
+ return response.messageId;
2474
+ }
2475
+ async leaveRoomAsync(room) {
2476
+ const response = await this.rpcClient.call(
2477
+ "H5_ROOM_LEAVE" /* H5_ROOM_LEAVE */,
2478
+ {
2479
+ roomId: room.id
2480
+ }
2481
+ );
2482
+ if (response?.success === false) {
2483
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to leave room";
2484
+ throw new Error(errorMessage);
2485
+ }
2486
+ }
2487
+ async startRoomGameAsync(room, options = {}) {
2488
+ const response = await this.rpcClient.call(
2489
+ "H5_ROOM_START_GAME" /* H5_ROOM_START_GAME */,
2490
+ {
2491
+ roomId: room.id,
2492
+ gameConfig: options.gameConfig ?? {},
2493
+ turnOrder: options.turnOrder ?? null
2494
+ }
2495
+ );
2496
+ if (response?.success === false) {
2497
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to start game";
2498
+ throw new Error(errorMessage);
2499
+ }
2500
+ }
2501
+ async proposeMoveAsync(room, proposalPayload) {
2502
+ const response = await this.rpcClient.call(
2503
+ "h5:room:proposeMove" /* H5_ROOM_PROPOSE_MOVE */,
2504
+ {
2505
+ roomId: room.id,
2506
+ gameSpecificState: proposalPayload.gameSpecificState,
2507
+ moveType: proposalPayload.moveType,
2508
+ clientContext: proposalPayload.clientContext,
2509
+ clientProposalId: proposalPayload.clientProposalId
2510
+ }
2511
+ );
2512
+ if (response?.success === false) {
2513
+ const errorMessage = typeof response.error === "string" ? response.error : "Failed to propose move";
2514
+ throw new Error(errorMessage);
2515
+ }
2516
+ return response.data;
2517
+ }
2518
+ async validateMoveAsync(_room, moveId, verdict) {
2519
+ return {
2520
+ success: true,
2521
+ moveId,
2522
+ isValid: verdict.isValid,
2523
+ reason: verdict.reason
2524
+ };
2525
+ }
2526
+ async subscribeAsync(room, options = {}) {
2527
+ const roomId = room.id;
2528
+ const existingData = this.subscriptions.data[roomId];
2529
+ const existingMessages = this.subscriptions.messages[roomId];
2530
+ const existingGameEvents = this.subscriptions.gameEvents[roomId];
2531
+ const subscribeToData = Boolean(options.onData) && (existingData?.length ?? 0) === 0;
2532
+ const subscribeToMessages = Boolean(options.onMessages) && (existingMessages?.length ?? 0) === 0;
2533
+ const subscribeToProposedMoves = Boolean(options.onGameEvents) && (existingGameEvents?.length ?? 0) === 0;
2534
+ if (subscribeToData || subscribeToMessages || subscribeToProposedMoves) {
2535
+ try {
2536
+ await this.rpcClient.call("H5_ROOM_SUBSCRIBE" /* H5_ROOM_SUBSCRIBE */, {
2537
+ roomId,
2538
+ subscribeToData,
2539
+ subscribeToMessages,
2540
+ subscribeToProposedMoves
2541
+ });
2542
+ } catch (error) {
2543
+ console.error("[Venus SDK] Failed to set up room subscription:", error);
2544
+ throw error;
2545
+ }
2546
+ }
2547
+ if (options.onData) {
2548
+ if (!this.subscriptions.data[roomId]) {
2549
+ this.subscriptions.data[roomId] = [];
2550
+ }
2551
+ this.subscriptions.data[roomId].push(options.onData);
2552
+ }
2553
+ if (options.onMessages) {
2554
+ if (!this.subscriptions.messages[roomId]) {
2555
+ this.subscriptions.messages[roomId] = [];
2556
+ }
2557
+ this.subscriptions.messages[roomId].push(options.onMessages);
2558
+ }
2559
+ if (options.onGameEvents) {
2560
+ if (!this.subscriptions.gameEvents[roomId]) {
2561
+ this.subscriptions.gameEvents[roomId] = [];
2562
+ }
2563
+ this.subscriptions.gameEvents[roomId].push(options.onGameEvents);
2564
+ }
2565
+ let disposed = false;
2566
+ return () => {
2567
+ if (disposed) return;
2568
+ disposed = true;
2569
+ if (options.onData) {
2570
+ const callbacks = this.subscriptions.data[roomId];
2571
+ if (callbacks) {
2572
+ const index = callbacks.indexOf(options.onData);
2573
+ if (index > -1) {
2574
+ callbacks.splice(index, 1);
2575
+ }
2576
+ }
2577
+ }
2578
+ if (options.onMessages) {
2579
+ const callbacks = this.subscriptions.messages[roomId];
2580
+ if (callbacks) {
2581
+ const index = callbacks.indexOf(options.onMessages);
2582
+ if (index > -1) {
2583
+ callbacks.splice(index, 1);
2584
+ }
2585
+ }
2586
+ }
2587
+ if (options.onGameEvents) {
2588
+ const callbacks = this.subscriptions.gameEvents[roomId];
2589
+ if (callbacks) {
2590
+ const index = callbacks.indexOf(options.onGameEvents);
2591
+ if (index > -1) {
2592
+ callbacks.splice(index, 1);
2593
+ }
2594
+ }
2595
+ }
2596
+ const hasAnySubscriptions = (this.subscriptions.data[roomId]?.length ?? 0) > 0 || (this.subscriptions.messages[roomId]?.length ?? 0) > 0 || (this.subscriptions.gameEvents[roomId]?.length ?? 0) > 0;
2597
+ if (!hasAnySubscriptions) {
2598
+ this.rpcClient.call("H5_ROOM_UNSUBSCRIBE" /* H5_ROOM_UNSUBSCRIBE */, {
2599
+ roomId
2600
+ }).catch((error) => {
2601
+ console.error("[Venus SDK] Failed to clean up room subscription:", error);
2602
+ });
2603
+ }
2604
+ };
2605
+ }
2606
+ };
2607
+
2608
+ // src/rooms/index.ts
2609
+ function bindMethod(target, targetKey, source, sourceKey) {
2610
+ const key = sourceKey ?? targetKey;
2611
+ const fn = source?.[key];
2612
+ if (typeof fn === "function") {
2613
+ target[targetKey] = fn.bind(source);
2614
+ return true;
2615
+ }
2616
+ return false;
2617
+ }
2618
+ function initializeRoomsApi(venusApi, host) {
2619
+ const roomsApi = host?.rooms;
2620
+ if (!roomsApi) {
2621
+ console.warn(
2622
+ "[Venus SDK] Host did not provide a rooms implementation. Rooms API will be unavailable."
2623
+ );
2624
+ return;
2625
+ }
2626
+ const venus = venusApi;
2627
+ const existingNamespace = venus.rooms || {};
2628
+ const roomsNamespace = Object.assign({}, existingNamespace);
2629
+ const namespaceBindings = [
2630
+ ["createRoomAsync"],
2631
+ ["joinOrCreateRoomAsync"],
2632
+ ["joinRoomByCodeAsync"],
2633
+ ["getUserRoomsAsync"],
2634
+ ["subscribeAsync"],
2635
+ ["updateRoomDataAsync"],
2636
+ ["getRoomDataAsync"],
2637
+ ["sendRoomMessageAsync"],
2638
+ ["leaveRoomAsync"],
2639
+ ["startRoomGameAsync"],
2640
+ ["proposeMoveAsync"],
2641
+ ["validateMoveAsync"]
2642
+ ];
2643
+ namespaceBindings.forEach(([targetKey, sourceKey]) => {
2644
+ bindMethod(roomsNamespace, targetKey, roomsApi, sourceKey);
2645
+ });
2646
+ venus.rooms = roomsNamespace;
2647
+ }
2648
+
2649
+ // src/storage/MockStorageApi.ts
2650
+ function createMockStorageApi(storageType, appUrl) {
2651
+ const appIdentifier = appUrl ? generateAppIdentifier(appUrl) : null;
2652
+ let prefix;
2653
+ let syncDelay = 0;
2654
+ switch (storageType) {
2655
+ case "deviceCache":
2656
+ prefix = "venus:app";
2657
+ syncDelay = 0;
2658
+ break;
2659
+ case "appStorage":
2660
+ prefix = "venus:app";
2661
+ syncDelay = 100;
2662
+ break;
2663
+ case "globalStorage":
2664
+ prefix = "venus:global";
2665
+ syncDelay = 100;
2666
+ break;
2667
+ default:
2668
+ throw new Error(`Unknown storage type: ${storageType}`);
2669
+ }
2670
+ prefix = storageType === "globalStorage" || !appIdentifier ? `${prefix}:` : `${prefix}:${appIdentifier}:`;
2671
+ return new MockStorageApi(prefix, syncDelay);
2672
+ }
2673
+ var MockStorageApi = class {
2674
+ constructor(prefix, syncDelay) {
2675
+ __publicField(this, "prefix");
2676
+ __publicField(this, "syncDelay");
2677
+ this.prefix = prefix;
2678
+ this.syncDelay = syncDelay;
2679
+ }
2680
+ async clear() {
2681
+ const fullLength = localStorage.length;
2682
+ for (let i = 0; i < fullLength; i++) {
2683
+ const fullKey = localStorage.key(i);
2684
+ if (fullKey && fullKey.startsWith(this.prefix)) {
2292
2685
  localStorage.removeItem(fullKey);
2293
2686
  }
2294
2687
  }
@@ -2486,24 +2879,20 @@ function initializeStorage(venusApiInstance, host) {
2486
2879
  venusApiInstance.globalStorage = host.globalStorage;
2487
2880
  }
2488
2881
 
2489
- // src/simulation/utils.ts
2490
- function sumContributions(contributions) {
2491
- const totals = {};
2492
- for (const profileId in contributions) {
2493
- for (const entityId in contributions[profileId]) {
2494
- const amount = contributions[profileId][entityId] || 0;
2495
- totals[entityId] = (totals[entityId] || 0) + amount;
2496
- }
2497
- }
2498
- return totals;
2499
- }
2500
-
2501
2882
  // src/simulation/RpcSimulationApi.ts
2502
2883
  var RpcSimulationApi = class {
2503
2884
  constructor(rpcClient) {
2504
2885
  __publicField(this, "rpcClient");
2505
2886
  __publicField(this, "_simulationConfig", null);
2887
+ __publicField(this, "subscriptionCallbacks", /* @__PURE__ */ new Map());
2506
2888
  this.rpcClient = rpcClient;
2889
+ this.rpcClient.onNotification(
2890
+ "H5_SIMULATION_UPDATE" /* H5_SIMULATION_UPDATE */,
2891
+ this.handleSimulationUpdate.bind(this)
2892
+ );
2893
+ }
2894
+ isEnabled() {
2895
+ return true;
2507
2896
  }
2508
2897
  async validateSlotAssignmentAsync(containerId, slotId, itemId) {
2509
2898
  return this.rpcClient.call(
@@ -2515,14 +2904,47 @@ var RpcSimulationApi = class {
2515
2904
  }
2516
2905
  );
2517
2906
  }
2518
- sumContributions(contributions) {
2519
- return sumContributions(contributions);
2907
+ async subscribeAsync(options) {
2908
+ this.ensureValidSubscribeOptions(options);
2909
+ const subscriptionId = generateId();
2910
+ this.subscriptionCallbacks.set(subscriptionId, options.onUpdate);
2911
+ try {
2912
+ await this.rpcClient.call("H5_SIMULATION_SUBSCRIBE" /* H5_SIMULATION_SUBSCRIBE */, {
2913
+ subscriptionId,
2914
+ entities: options.entities,
2915
+ tags: options.tags,
2916
+ activeRuns: options.activeRuns,
2917
+ roomId: options.roomId
2918
+ });
2919
+ } catch (error) {
2920
+ this.subscriptionCallbacks.delete(subscriptionId);
2921
+ throw error;
2922
+ }
2923
+ let unsubscribed = false;
2924
+ return () => {
2925
+ if (unsubscribed) {
2926
+ return;
2927
+ }
2928
+ unsubscribed = true;
2929
+ this.subscriptionCallbacks.delete(subscriptionId);
2930
+ void this.rpcClient.call("H5_SIMULATION_UNSUBSCRIBE" /* H5_SIMULATION_UNSUBSCRIBE */, {
2931
+ subscriptionId
2932
+ }).catch((error) => {
2933
+ console.error(
2934
+ "[Venus SDK] Failed to unsubscribe simulation listener",
2935
+ error
2936
+ );
2937
+ });
2938
+ };
2520
2939
  }
2521
2940
  executeBatchOperationsAsync(operations, validateOnly) {
2522
- return this.rpcClient.call("H5_SIMULATION_BATCH_OPERATIONS" /* H5_SIMULATION_BATCH_OPERATIONS */, {
2523
- operations,
2524
- validateOnly
2525
- });
2941
+ return this.rpcClient.call(
2942
+ "H5_SIMULATION_BATCH_OPERATIONS" /* H5_SIMULATION_BATCH_OPERATIONS */,
2943
+ {
2944
+ operations,
2945
+ validateOnly
2946
+ }
2947
+ );
2526
2948
  }
2527
2949
  async getAvailableItemsAsync(containerId, slotId) {
2528
2950
  const response = await this.rpcClient.call(
@@ -2545,17 +2967,23 @@ var RpcSimulationApi = class {
2545
2967
  );
2546
2968
  }
2547
2969
  assignItemToSlotAsync(containerId, slotId, itemId) {
2548
- return this.rpcClient.call("H5_SIMULATION_ASSIGN_ITEM" /* H5_SIMULATION_ASSIGN_ITEM */, {
2549
- containerId,
2550
- slotId,
2551
- itemId
2552
- });
2970
+ return this.rpcClient.call(
2971
+ "H5_SIMULATION_ASSIGN_ITEM" /* H5_SIMULATION_ASSIGN_ITEM */,
2972
+ {
2973
+ containerId,
2974
+ slotId,
2975
+ itemId
2976
+ }
2977
+ );
2553
2978
  }
2554
2979
  removeItemFromSlotAsync(containerId, slotId) {
2555
- return this.rpcClient.call("H5_SIMULATION_REMOVE_ITEM" /* H5_SIMULATION_REMOVE_ITEM */, {
2556
- containerId,
2557
- slotId
2558
- });
2980
+ return this.rpcClient.call(
2981
+ "H5_SIMULATION_REMOVE_ITEM" /* H5_SIMULATION_REMOVE_ITEM */,
2982
+ {
2983
+ containerId,
2984
+ slotId
2985
+ }
2986
+ );
2559
2987
  }
2560
2988
  async getSlotContainersAsync() {
2561
2989
  const response = await this.rpcClient.call(
@@ -2580,7 +3008,6 @@ var RpcSimulationApi = class {
2580
3008
  roomId
2581
3009
  }
2582
3010
  );
2583
- console.log("[Venus SDK] getStateAsync", response);
2584
3011
  if (response.configuration) {
2585
3012
  this._simulationConfig = response.configuration;
2586
3013
  }
@@ -2592,9 +3019,10 @@ var RpcSimulationApi = class {
2592
3019
  }
2593
3020
  const config = await this.rpcClient.call(
2594
3021
  "H5_SIMULATION_GET_CONFIG" /* H5_SIMULATION_GET_CONFIG */,
2595
- {}
3022
+ {
3023
+ roomId
3024
+ }
2596
3025
  );
2597
- console.log("[Venus SDK] getConfigAsync", config);
2598
3026
  if (config) {
2599
3027
  this._simulationConfig = config;
2600
3028
  return config;
@@ -2602,14 +3030,17 @@ var RpcSimulationApi = class {
2602
3030
  throw new Error("No simulation configuration available");
2603
3031
  }
2604
3032
  executeRecipeAsync(recipeId, inputs, options) {
2605
- return this.rpcClient.call("H5_SIMULATION_EXECUTE_RECIPE" /* H5_SIMULATION_EXECUTE_RECIPE */, {
2606
- recipeId,
2607
- inputs,
2608
- roomId: options?.roomId,
2609
- batchAmount: options?.batchAmount,
2610
- allowPartialBatch: options?.allowPartialBatch,
2611
- entity: options?.entity
2612
- });
3033
+ return this.rpcClient.call(
3034
+ "H5_SIMULATION_EXECUTE_RECIPE" /* H5_SIMULATION_EXECUTE_RECIPE */,
3035
+ {
3036
+ recipeId,
3037
+ inputs,
3038
+ roomId: options?.roomId,
3039
+ batchAmount: options?.batchAmount,
3040
+ allowPartialBatch: options?.allowPartialBatch,
3041
+ entity: options?.entity
3042
+ }
3043
+ );
2613
3044
  }
2614
3045
  collectRecipeAsync(runId) {
2615
3046
  return this.rpcClient.call("H5_SIMULATION_COLLECT_RECIPE" /* H5_SIMULATION_COLLECT_RECIPE */, {
@@ -2617,9 +3048,12 @@ var RpcSimulationApi = class {
2617
3048
  });
2618
3049
  }
2619
3050
  getActiveRunsAsync(options) {
2620
- return this.rpcClient.call("H5_SIMULATION_GET_ACTIVE_RUNS" /* H5_SIMULATION_GET_ACTIVE_RUNS */, {
2621
- roomId: options?.roomId
2622
- });
3051
+ return this.rpcClient.call(
3052
+ "H5_SIMULATION_GET_ACTIVE_RUNS" /* H5_SIMULATION_GET_ACTIVE_RUNS */,
3053
+ {
3054
+ roomId: options?.roomId
3055
+ }
3056
+ );
2623
3057
  }
2624
3058
  executeScopedRecipeAsync(recipeId, entity, inputs, options) {
2625
3059
  return this.rpcClient.call(
@@ -2637,635 +3071,104 @@ var RpcSimulationApi = class {
2637
3071
  return this.rpcClient.call(
2638
3072
  "H5_SIMULATION_GET_AVAILABLE_RECIPES" /* H5_SIMULATION_GET_AVAILABLE_RECIPES */,
2639
3073
  {
2640
- roomId: options?.roomId || null,
2641
- includeActorRecipes: options?.includeActorRecipes || false
2642
- }
2643
- );
2644
- }
2645
- getRecipeRequirementsAsync(recipe) {
2646
- return this.rpcClient.call(
2647
- "H5_SIMULATION_GET_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_RECIPE_REQUIREMENTS */,
2648
- {
2649
- recipeId: recipe.recipeId,
2650
- entity: recipe.entity,
2651
- batchAmount: recipe.batchAmount
2652
- }
2653
- );
2654
- }
2655
- getBatchRecipeRequirementsAsync(recipes) {
2656
- return this.rpcClient.call(
2657
- "H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS */,
2658
- {
2659
- recipes
2660
- }
2661
- );
2662
- }
2663
- triggerRecipeChainAsync(recipeId, options) {
2664
- return this.rpcClient.call(
2665
- "H5_SIMULATION_TRIGGER_RECIPE_CHAIN" /* H5_SIMULATION_TRIGGER_RECIPE_CHAIN */,
2666
- {
2667
- triggerRecipeId: recipeId,
2668
- context: options?.context,
2669
- roomId: options?.roomId
2670
- }
2671
- );
2672
- }
2673
- getEntityMetadataAsync(entityId) {
2674
- return this.rpcClient.call(
2675
- "H5_SIMULATION_GET_ENTITY_METADATA" /* H5_SIMULATION_GET_ENTITY_METADATA */,
2676
- {
2677
- entityId
2678
- }
2679
- );
2680
- }
2681
- async resolveFieldValueAsync(entityId, fieldPath, entity) {
2682
- const response = await this.rpcClient.call(
2683
- "H5_SIMULATION_RESOLVE_VALUE" /* H5_SIMULATION_RESOLVE_VALUE */,
2684
- {
2685
- entityId,
2686
- fieldPath,
2687
- entity
2688
- }
2689
- );
2690
- return response.value;
2691
- }
2692
- };
2693
-
2694
- // src/simulation/MockSimulationApi.ts
2695
- function generateAppIdentifier2() {
2696
- if (typeof window === "undefined") return "unknown-app";
2697
- const url = window.location.href;
2698
- const match = url.match(/\/H5\/([^\/]+)/);
2699
- return match ? match[1] : "unknown-app";
2700
- }
2701
- var MockSimulationApi = class {
2702
- constructor(simulationConfig = null) {
2703
- __publicField(this, "mockSimulationConfigs", /* @__PURE__ */ new Map());
2704
- // appIdentifier -> config
2705
- __publicField(this, "mockSimulationStates", /* @__PURE__ */ new Map());
2706
- // appIdentifier -> config
2707
- __publicField(this, "mockActiveTimers", /* @__PURE__ */ new Map());
2708
- // appIdentifier -> timers[]
2709
- __publicField(this, "appId");
2710
- __publicField(this, "providedSimulationConfig");
2711
- this.appId = generateAppIdentifier2();
2712
- this.providedSimulationConfig = simulationConfig;
2713
- }
2714
- sumContributions(contributions) {
2715
- return sumContributions(contributions);
2716
- }
2717
- async validateSlotAssignmentAsync(containerId, slotId, itemId) {
2718
- this.log("validateSlotAssignmentAsync called:", {
2719
- containerId,
2720
- slotId,
2721
- itemId
2722
- });
2723
- return { valid: true, message: "Mock validation successful" };
2724
- }
2725
- async executeBatchOperationsAsync(operations, validateOnly) {
2726
- this.log("executeBatchOperationsAsync called:", {
2727
- operations,
2728
- validateOnly
2729
- });
2730
- return {
2731
- success: true,
2732
- results: operations.map(() => ({ success: true }))
2733
- };
2734
- }
2735
- async getAvailableItemsAsync(containerId, slotId) {
2736
- console.log("[Venus Simulation Mock] getAvailableItemsAsync called:", {
2737
- containerId,
2738
- slotId
2739
- });
2740
- const appIdentifier = generateAppIdentifier2();
2741
- const mockSimulationConfigs = this.mockSimulationConfigs;
2742
- const config = mockSimulationConfigs.get(appIdentifier) || {
2743
- entities: {}
2744
- };
2745
- const availableItems = Object.entries(config.entities).slice(0, 3).map(([entityId, entity]) => ({
2746
- entityId,
2747
- quantity: 1,
2748
- metadata: entity.metadata,
2749
- powerPreview: 100
2750
- // Mock power value
2751
- }));
2752
- return availableItems;
2753
- }
2754
- async calculatePowerPreviewAsync(containerId, slotId, candidateItemId) {
2755
- this.log("calculatePowerPreviewAsync called:", {
2756
- containerId,
2757
- slotId,
2758
- candidateItemId
2759
- });
2760
- return {
2761
- currentPower: 1e3,
2762
- previewPower: 1200,
2763
- powerDelta: 200,
2764
- breakdown: { base: 800, weapon: 200, armor: 200 }
2765
- };
2766
- }
2767
- async getSlotContainersAsync() {
2768
- this.log("getSlotContainersAsync called");
2769
- const appIdentifier = this.appId;
2770
- const mockSimulationConfigs = this.mockSimulationConfigs;
2771
- const config = mockSimulationConfigs.get(appIdentifier) || {
2772
- entities: {}
2773
- };
2774
- const containers = Object.entries(config.entities).filter(([_, entity]) => entity.metadata?.slots).map(([entityId, entity]) => ({
2775
- entityId,
2776
- slots: entity.metadata?.slots,
2777
- isOwned: true
2778
- // Mock: assume all containers are owned
2779
- }));
2780
- return containers;
2781
- }
2782
- async getSlotAssignmentsAsync(containerId) {
2783
- this.log("getSlotAssignmentsAsync called for:", containerId);
2784
- return [];
2785
- }
2786
- async resolveFieldValueAsync(entityId, fieldPath, entity) {
2787
- this.log("resolveFieldValueAsync called:", {
2788
- entityId,
2789
- fieldPath,
2790
- entity
2791
- });
2792
- const mockValues = {
2793
- basePower: 850,
2794
- weaponPower: 300,
2795
- armorPower: 150,
2796
- total_power: 1300,
2797
- total_defense_power: 5e3
2798
- };
2799
- return mockValues[fieldPath] || 100;
2800
- }
2801
- async getEntityMetadataAsync(entityId) {
2802
- this.log("getEntityMetadataAsync called for:", entityId);
2803
- const mockSimulationConfigs = this.mockSimulationConfigs;
2804
- const appIdentifier = this.appId;
2805
- const config = mockSimulationConfigs.get(
2806
- appIdentifier
2807
- ) || {
2808
- entities: {}};
2809
- const entity = config.entities[entityId];
2810
- return entity?.metadata || {};
2811
- }
2812
- async collectRecipeAsync(runId) {
2813
- this.log("collectRecipeAsync called:", { runId });
2814
- const mockRewards = {
2815
- cash: Math.floor(Math.random() * 1e3) + 500,
2816
- experience: Math.floor(Math.random() * 50) + 25
2817
- };
2818
- return {
2819
- success: true,
2820
- runId,
2821
- rewards: mockRewards,
2822
- message: "Rewards collected successfully"
2823
- };
2824
- }
2825
- executeRecipeAsync(recipeId, inputs, options) {
2826
- this.log("executeRecipeAsync called:", {
2827
- recipeId,
2828
- inputs,
2829
- options
2830
- });
2831
- const appIdentifier = this.appId;
2832
- return this.executeRecipe(appIdentifier, recipeId, inputs);
2833
- }
2834
- async executeScopedRecipeAsync(recipeId, entity, inputs, options) {
2835
- this.log("executeScopedRecipeAsync called:", {
2836
- recipeId,
2837
- entity,
2838
- inputs,
2839
- roomId: options?.roomId,
2840
- options
2841
- });
2842
- return {
2843
- success: true,
2844
- message: "Mock scoped recipe execution successful"
2845
- };
2846
- }
2847
- async getActiveRunsAsync(options) {
2848
- this.log("getActiveRunsAsync called:", options);
2849
- const appIdentifier = this.appId;
2850
- let state = this.mockSimulationStates.get(appIdentifier);
2851
- if (!state) {
2852
- state = await this.initializeSimulationState(appIdentifier);
2853
- }
2854
- return state.activeRuns || [];
2855
- }
2856
- async getAvailableRecipesAsync(options) {
2857
- this.log("getAvailableRecipesAsync called:", options);
2858
- const baseRecipes = [
2859
- { id: "collect_resources", scope: "player", clientViewable: true },
2860
- { id: "upgrade_equipment", scope: "player", clientViewable: true }
2861
- ];
2862
- if (options?.roomId) {
2863
- baseRecipes.push(
2864
- { id: "room_upgrade", scope: "room", clientViewable: true },
2865
- { id: "cooperative_project", scope: "room", clientViewable: true }
2866
- );
2867
- }
2868
- if (options?.includeActorRecipes && options?.roomId) {
2869
- baseRecipes.push(
2870
- { id: "trade_with_npc", scope: "actor", clientViewable: true },
2871
- { id: "attack_monster", scope: "actor", clientViewable: true }
2872
- );
2873
- }
2874
- return { success: true, recipes: baseRecipes };
2875
- }
2876
- async getBatchRecipeRequirementsAsync(recipes) {
2877
- this.log("getBatchRecipeRequirementsAsync called:", {
2878
- count: recipes?.length
2879
- });
2880
- const results = (recipes || []).map((q) => ({
2881
- recipeId: q.recipeId,
2882
- entity: q.entity || null,
2883
- amount: q.batchAmount || 1,
2884
- inputs: { cash: "BE:0" },
2885
- canAfford: true,
2886
- disabled: false
2887
- }));
2888
- return { success: true, results };
2889
- }
2890
- async getRecipeRequirementsAsync(recipe) {
2891
- this.log("getRecipeRequirementsAsync called:", recipe);
2892
- return {
2893
- recipeId: recipe.recipeId,
2894
- entity: recipe.entity || null,
2895
- amount: recipe.batchAmount,
2896
- inputs: { cash: "BE:0" },
2897
- canAfford: true,
2898
- disabled: false
2899
- };
2900
- }
2901
- async triggerRecipeChainAsync(recipeId, options) {
2902
- this.log("triggerRecipeChainAsync called:", { recipeId, ...options });
2903
- return {
2904
- success: true,
2905
- message: "Mock recipe chain triggered successfully"
2906
- };
2907
- }
2908
- log(message, ...args) {
2909
- console.log(`[Venus Sim Mock] ${message}`, args);
2910
- }
2911
- async executeRecipe(appIdentifier, recipeId, inputs) {
2912
- this.log(`Executing recipe ${recipeId} for ${appIdentifier}`, inputs);
2913
- const mockSimulationConfigs = this.mockSimulationConfigs;
2914
- const mockSimulationStates = this.mockSimulationStates;
2915
- let config = mockSimulationConfigs.get(appIdentifier);
2916
- let state = mockSimulationStates.get(appIdentifier);
2917
- if (!config || !state) {
2918
- state = await this.initializeSimulationState(appIdentifier);
2919
- config = mockSimulationConfigs.get(appIdentifier);
2920
- if (!config) {
2921
- throw new Error("Failed to initialize simulation config");
2922
- }
2923
- }
2924
- const recipe = config.recipes?.[recipeId];
2925
- if (!recipe) {
2926
- throw new Error(`Recipe ${recipeId} not found`);
2927
- }
2928
- if (state.disabledRecipes?.includes(recipeId)) {
2929
- throw new Error(`Recipe ${recipeId} is disabled`);
2930
- }
2931
- if (recipe.inputs) {
2932
- for (const [entityId, required] of Object.entries(recipe.inputs)) {
2933
- const available = state.inventory[entityId] || 0;
2934
- if (available < required) {
2935
- throw new Error(
2936
- `Insufficient ${entityId}: required ${required}, available ${available}`
2937
- );
2938
- }
2939
- }
2940
- }
2941
- if (recipe.inputs) {
2942
- for (const [entityId, input] of Object.entries(recipe.inputs)) {
2943
- const inventoryValue = state.inventory[entityId] || 0;
2944
- if (typeof input === "number" && typeof inventoryValue === "number") {
2945
- state.inventory[entityId] = inventoryValue - input;
2946
- }
2947
- }
2948
- }
2949
- if (recipe.beginEffects) {
2950
- this.applyEffects(state, recipe.beginEffects);
2951
- }
2952
- const runId = this.generateRunId();
2953
- const now = Date.now();
2954
- const expiresAt = now + (recipe.duration || 0);
2955
- const run = {
2956
- id: runId,
2957
- recipeId,
2958
- status: "running",
2959
- startTime: now,
2960
- expiresAt,
2961
- inputs: recipe.inputs || {}
2962
- };
2963
- state.activeRuns.push(run);
2964
- if (recipe.duration === 0) {
2965
- this.completeRun(appIdentifier, runId);
2966
- return { status: "completed", runId };
2967
- } else {
2968
- const mockActiveTimers = this.mockActiveTimers;
2969
- const timer = setTimeout(() => {
2970
- this.completeRun(appIdentifier, runId);
2971
- }, recipe.duration);
2972
- const timers = mockActiveTimers.get(appIdentifier) || [];
2973
- timers.push(timer);
2974
- mockActiveTimers.set(appIdentifier, timers);
2975
- return {
2976
- status: "running",
2977
- runId,
2978
- expiresAt: new Date(expiresAt).toISOString()
2979
- };
2980
- }
2981
- }
2982
- async initializeSimulationState(appIdentifier) {
2983
- this.log(`Initializing simulation state for ${appIdentifier}`);
2984
- const providedSimulationConfig = this.providedSimulationConfig;
2985
- const mockSimulationConfigs = this.mockSimulationConfigs;
2986
- const mockSimulationStates = this.mockSimulationStates;
2987
- const mockActiveTimers = this.mockActiveTimers;
2988
- const config = providedSimulationConfig || {
2989
- version: "1.0",
2990
- entities: {},
2991
- recipes: {}
2992
- };
2993
- mockSimulationConfigs.set(appIdentifier, config);
2994
- const initialInventory = {};
2995
- if (providedSimulationConfig && config.entities) {
2996
- Object.keys(config.entities).forEach((entityId) => {
2997
- initialInventory[entityId] = 0;
2998
- });
2999
- }
3000
- const state = {
3001
- inventory: initialInventory,
3002
- activeRuns: [],
3003
- disabledRecipes: new Array()
3004
- };
3005
- if (config.recipes) {
3006
- Object.entries(config.recipes).forEach(([recipeId, recipe]) => {
3007
- if (recipe.metadata?.startsDisabled) {
3008
- state.disabledRecipes.push(recipeId);
3009
- }
3010
- });
3011
- }
3012
- mockSimulationStates.set(appIdentifier, state);
3013
- mockActiveTimers.set(appIdentifier, []);
3014
- console.log(
3015
- `[Venus Simulation Mock] Initialized state for ${appIdentifier}:`,
3016
- state
3017
- );
3018
- if (config.recipes) {
3019
- Object.entries(config.recipes).forEach(([recipeId, recipe]) => {
3020
- const isAutoRestart = recipe.autoRestart || recipe.metadata?.autoRestart;
3021
- if (isAutoRestart && recipe.outputs) {
3022
- this.log(`Found auto-restart recipe: ${recipeId}`, {
3023
- topLevelAutoRestart: recipe.autoRestart,
3024
- metadataAutoRestart: recipe.metadata?.autoRestart,
3025
- hasOutputs: !!recipe.outputs,
3026
- duration: recipe.duration
3027
- });
3028
- const condition = recipe.maxRestartCondition || recipe.metadata?.maxRestartCondition;
3029
- if (condition && condition.entity) {
3030
- const currentAmount = initialInventory[condition.entity] || 0;
3031
- if (currentAmount < condition.maxValue) {
3032
- console.log(
3033
- `[Venus Simulation Mock] Auto-starting ${recipeId} at initialization`,
3034
- {
3035
- currentAmount,
3036
- maxValue: condition.maxValue,
3037
- entity: condition.entity
3038
- }
3039
- );
3040
- setTimeout(() => {
3041
- this.executeRecipe(appIdentifier, recipeId, {});
3042
- }, 1e3);
3043
- }
3044
- } else {
3045
- console.log(
3046
- `[Venus Simulation Mock] Auto-starting ${recipeId} at initialization (no condition)`
3047
- );
3048
- setTimeout(() => {
3049
- this.executeRecipe(appIdentifier, recipeId, {});
3050
- }, 1e3);
3051
- }
3052
- }
3053
- });
3054
- }
3055
- return state;
3056
- }
3057
- generateRunId() {
3058
- return "run_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
3059
- }
3060
- completeRun(appIdentifier, runId) {
3061
- this.log(`Completing run ${runId} for ${appIdentifier}`);
3062
- const mockSimulationConfigs = this.mockSimulationConfigs;
3063
- const mockSimulationStates = this.mockSimulationStates;
3064
- const config = mockSimulationConfigs.get(appIdentifier);
3065
- const state = mockSimulationStates.get(appIdentifier);
3066
- if (!config || !state) return;
3067
- const runIndex = state.activeRuns.findIndex((r) => r.id === runId);
3068
- if (runIndex === -1) return;
3069
- const run = state.activeRuns[runIndex];
3070
- const recipe = config.recipes?.[run.recipeId];
3071
- if (!recipe) return;
3072
- const outputs = {};
3073
- const rng = this.createSeededRandom(runId);
3074
- if (recipe.outputs) {
3075
- for (const [entityId, value] of Object.entries(recipe.outputs)) {
3076
- if (typeof value === "number") {
3077
- outputs[entityId] = value;
3078
- } else if (typeof value === "object" && value != null && "min" in value && "max" in value && typeof value.min == "number" && typeof value.max === "number") {
3079
- outputs[entityId] = Math.floor(rng() * (value.max - value.min + 1)) + value.min;
3080
- }
3074
+ roomId: options?.roomId || null,
3075
+ includeActorRecipes: options?.includeActorRecipes || false
3081
3076
  }
3082
- }
3083
- for (const [entityId, amount] of Object.entries(outputs)) {
3084
- state.inventory[entityId] = (state.inventory[entityId] || 0) + amount;
3085
- }
3086
- if (recipe.endEffects) {
3087
- this.applyEffects(state, recipe.endEffects);
3088
- }
3089
- run.status = "completed";
3090
- run.outputs = outputs;
3091
- state.activeRuns.splice(runIndex, 1);
3092
- const isAutoRestart = recipe.autoRestart || recipe.metadata?.autoRestart;
3093
- if (isAutoRestart) {
3094
- console.log(
3095
- `[Venus Simulation Mock] Checking auto-restart for ${run.recipeId}`,
3096
- {
3097
- topLevelAutoRestart: recipe.autoRestart,
3098
- metadataAutoRestart: recipe.metadata?.autoRestart,
3099
- hasCondition: !!(recipe.maxRestartCondition || recipe.metadata?.maxRestartCondition)
3100
- }
3101
- );
3102
- const condition = recipe.maxRestartCondition || recipe.metadata?.maxRestartCondition;
3103
- if (condition) {
3104
- const currentAmount = state.inventory[condition.entity] || 0;
3105
- if (currentAmount < condition.maxValue) {
3106
- console.log(
3107
- `[Venus Simulation Mock] Auto-restarting ${run.recipeId}`,
3108
- {
3109
- currentAmount,
3110
- maxValue: condition.maxValue,
3111
- entity: condition.entity
3112
- }
3113
- );
3114
- setTimeout(() => {
3115
- this.executeRecipe(appIdentifier, run.recipeId, recipe.inputs || {});
3116
- }, 1e3);
3117
- }
3118
- } else {
3119
- console.log(
3120
- `[Venus Simulation Mock] Auto-restarting ${run.recipeId} (no condition)`
3121
- );
3122
- setTimeout(() => {
3123
- this.executeRecipe(appIdentifier, run.recipeId, recipe.inputs || {});
3124
- }, 1e3);
3077
+ );
3078
+ }
3079
+ getRecipeRequirementsAsync(recipe) {
3080
+ return this.rpcClient.call(
3081
+ "H5_SIMULATION_GET_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_RECIPE_REQUIREMENTS */,
3082
+ {
3083
+ recipeId: recipe.recipeId,
3084
+ entity: recipe.entity,
3085
+ batchAmount: recipe.batchAmount
3125
3086
  }
3126
- }
3127
- console.log(
3128
- `[Venus Simulation Mock] Completed run ${runId}, outputs:`,
3129
- outputs
3130
3087
  );
3131
3088
  }
3132
- createSeededRandom(seed) {
3133
- let hash = 0;
3134
- for (let i = 0; i < seed.length; i++) {
3135
- const char = seed.charCodeAt(i);
3136
- hash = (hash << 5) - hash + char;
3137
- hash = hash & hash;
3138
- }
3139
- return () => {
3140
- hash = (hash * 9301 + 49297) % 233280;
3141
- return hash / 233280;
3142
- };
3089
+ getBatchRecipeRequirementsAsync(recipes) {
3090
+ return this.rpcClient.call(
3091
+ "H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS" /* H5_SIMULATION_GET_BATCH_RECIPE_REQUIREMENTS */,
3092
+ {
3093
+ recipes
3094
+ }
3095
+ );
3143
3096
  }
3144
- applyEffects(state, effects) {
3145
- if (!effects || !Array.isArray(effects)) return;
3146
- for (const effect of effects) {
3147
- switch (effect.type) {
3148
- case "set":
3149
- state.inventory[effect.target] = effect.value;
3150
- console.log(
3151
- `[Venus Simulation Mock] Effect: Set ${effect.target} = ${effect.value}`
3152
- );
3153
- break;
3154
- case "add":
3155
- state.inventory[effect.target] = (state.inventory[effect.target] || 0) + effect.value;
3156
- console.log(
3157
- `[Venus Simulation Mock] Effect: Add ${effect.value} to ${effect.target} (new value: ${state.inventory[effect.target]})`
3158
- );
3159
- break;
3160
- case "multiply":
3161
- state.inventory[effect.target] = (state.inventory[effect.target] || 0) * effect.value;
3162
- console.log(
3163
- `[Venus Simulation Mock] Effect: Multiply ${effect.target} by ${effect.value} (new value: ${state.inventory[effect.target]})`
3164
- );
3165
- break;
3166
- case "min":
3167
- state.inventory[effect.target] = Math.max(
3168
- state.inventory[effect.target] || 0,
3169
- effect.value
3170
- );
3171
- console.log(
3172
- `[Venus Simulation Mock] Effect: Set ${effect.target} min ${effect.value} (new value: ${state.inventory[effect.target]})`
3173
- );
3174
- break;
3175
- case "max":
3176
- state.inventory[effect.target] = Math.min(
3177
- state.inventory[effect.target] || 0,
3178
- effect.value
3179
- );
3180
- console.log(
3181
- `[Venus Simulation Mock] Effect: Set ${effect.target} max ${effect.value} (new value: ${state.inventory[effect.target]})`
3182
- );
3183
- break;
3184
- case "enable_recipe":
3185
- if (state.disabledRecipes?.includes(effect.target)) {
3186
- state.disabledRecipes = state.disabledRecipes.filter(
3187
- (r) => r !== effect.target
3188
- );
3189
- console.log(
3190
- `[Venus Simulation Mock] Effect: Enabled recipe ${effect.target}`
3191
- );
3192
- }
3193
- break;
3194
- case "disable_recipe":
3195
- if (!state.disabledRecipes) state.disabledRecipes = [];
3196
- if (!state.disabledRecipes.includes(effect.target)) {
3197
- state.disabledRecipes.push(effect.target);
3198
- console.log(
3199
- `[Venus Simulation Mock] Effect: Disabled recipe ${effect.target}`
3200
- );
3201
- }
3202
- break;
3203
- case "trigger_recipe":
3204
- console.log(
3205
- `[Venus Simulation Mock] Effect: Trigger recipe ${effect.target} (not implemented)`
3206
- );
3207
- break;
3208
- default:
3209
- console.warn(
3210
- `[Venus Simulation Mock] Unknown effect type: ${effect.type}`
3211
- );
3097
+ triggerRecipeChainAsync(recipeId, options) {
3098
+ return this.rpcClient.call(
3099
+ "H5_SIMULATION_TRIGGER_RECIPE_CHAIN" /* H5_SIMULATION_TRIGGER_RECIPE_CHAIN */,
3100
+ {
3101
+ triggerRecipeId: recipeId,
3102
+ context: options?.context,
3103
+ roomId: options?.roomId
3212
3104
  }
3213
- }
3105
+ );
3214
3106
  }
3215
- async getConfigAsync() {
3216
- console.log("[Venus Simulation Mock] getConfigAsync called");
3217
- const appIdentifier = this.appId;
3218
- const mockSimulationConfigs = this.mockSimulationConfigs;
3219
- const config = mockSimulationConfigs.get(appIdentifier) || {
3220
- version: "1.0",
3221
- entities: {},
3222
- recipes: {}
3223
- };
3224
- return config;
3107
+ getEntityMetadataAsync(entityId) {
3108
+ return this.rpcClient.call(
3109
+ "H5_SIMULATION_GET_ENTITY_METADATA" /* H5_SIMULATION_GET_ENTITY_METADATA */,
3110
+ {
3111
+ entityId
3112
+ }
3113
+ );
3225
3114
  }
3226
- async getStateAsync(roomId) {
3227
- this.log("getStateAsync called:", roomId);
3228
- const appIdentifier = this.appId;
3229
- const mockSimulationStates = this.mockSimulationStates;
3230
- let state = mockSimulationStates.get(appIdentifier);
3231
- if (!state) {
3232
- state = await this.initializeSimulationState(appIdentifier);
3233
- }
3234
- const mockSimulationConfigs = this.mockSimulationConfigs;
3235
- return {
3236
- ...state,
3237
- roomId,
3238
- configuration: mockSimulationConfigs.get(appIdentifier)
3239
- };
3115
+ async resolveFieldValueAsync(entityId, fieldPath, entity) {
3116
+ const response = await this.rpcClient.call(
3117
+ "H5_SIMULATION_RESOLVE_VALUE" /* H5_SIMULATION_RESOLVE_VALUE */,
3118
+ {
3119
+ entityId,
3120
+ fieldPath,
3121
+ entity
3122
+ }
3123
+ );
3124
+ return response.value;
3240
3125
  }
3241
- async assignItemToSlotAsync(containerId, slotId, itemId) {
3242
- this.log("assignItemToSlotAsync called:", {
3243
- containerId,
3244
- slotId,
3245
- itemId
3246
- });
3247
- return { success: true, message: "Mock assignment successful" };
3126
+ handleSimulationUpdate(notification) {
3127
+ if (!notification || !notification.subscriptionId) {
3128
+ console.warn("[Venus SDK] Received malformed simulation update");
3129
+ return;
3130
+ }
3131
+ const callback = this.subscriptionCallbacks.get(notification.subscriptionId);
3132
+ if (!callback) {
3133
+ console.warn(
3134
+ "[Venus SDK] Received update for unknown subscription:",
3135
+ notification.subscriptionId
3136
+ );
3137
+ return;
3138
+ }
3139
+ try {
3140
+ callback(notification.updates);
3141
+ } catch (error) {
3142
+ console.error("[Venus SDK] Error in simulation subscription callback", error);
3143
+ }
3248
3144
  }
3249
- async removeItemFromSlotAsync(containerId, slotId) {
3250
- this.log("removeItemFromSlotAsync called:", {
3251
- containerId,
3252
- slotId
3253
- });
3254
- return { success: true, message: "Mock removal successful" };
3145
+ ensureValidSubscribeOptions(options) {
3146
+ if (typeof options !== "object" || options === null) {
3147
+ throw new Error("Simulation subscribe requires an options object");
3148
+ }
3149
+ const opts = options;
3150
+ if (typeof opts.onUpdate !== "function") {
3151
+ throw new Error("Simulation subscribe requires an onUpdate callback");
3152
+ }
3153
+ const hasFilter = Array.isArray(opts.entities) && opts.entities.length > 0 || Array.isArray(opts.tags) && opts.tags.length > 0 || Boolean(opts.activeRuns);
3154
+ if (!hasFilter) {
3155
+ throw new Error(
3156
+ "Simulation subscribe requires at least one filter (entities, tags, activeRuns)"
3157
+ );
3158
+ }
3255
3159
  }
3256
3160
  };
3257
3161
 
3258
3162
  // src/simulation/index.ts
3259
3163
  function initializeSimulation(venusApi, host) {
3260
- console.log("[Venus SDK] Initializing new Simulation Api");
3261
3164
  venusApi.simulation = {
3262
3165
  isEnabled: () => true
3263
3166
  };
3264
3167
  venusApi.simulation.getConfigAsync = () => {
3265
3168
  return host.simulation.getConfigAsync();
3266
3169
  };
3267
- venusApi.simulation.getStateAsync = (options) => {
3268
- return host.simulation.getStateAsync(options?.roomId);
3170
+ venusApi.simulation.getStateAsync = (roomId) => {
3171
+ return host.simulation.getStateAsync(roomId);
3269
3172
  };
3270
3173
  venusApi.simulation.executeRecipeAsync = (recipeId, inputs, options) => {
3271
3174
  return host.simulation.executeRecipeAsync(recipeId, inputs, options);
@@ -3276,31 +3179,17 @@ function initializeSimulation(venusApi, host) {
3276
3179
  venusApi.simulation.collectRecipeAsync = (runId) => {
3277
3180
  return host.simulation.collectRecipeAsync(runId);
3278
3181
  };
3279
- venusApi.simulation.executeScopedRecipeAsync = (recipeId, entity, inputs, roomId, options) => {
3280
- return host.simulation.executeScopedRecipeAsync(recipeId, entity, inputs, {
3281
- roomId,
3282
- ...options
3283
- });
3182
+ venusApi.simulation.executeScopedRecipeAsync = (recipeId, entity, inputs, options) => {
3183
+ return host.simulation.executeScopedRecipeAsync(recipeId, entity, inputs, options);
3284
3184
  };
3285
- venusApi.simulation.triggerRecipeChainAsync = (recipeId, context, roomId) => {
3286
- return host.simulation.triggerRecipeChainAsync(recipeId, {
3287
- context,
3288
- roomId
3289
- });
3185
+ venusApi.simulation.triggerRecipeChainAsync = (recipeId, options) => {
3186
+ return host.simulation.triggerRecipeChainAsync(recipeId, options);
3290
3187
  };
3291
- venusApi.simulation.getAvailableRecipesAsync = async (roomId, includeActorRecipes) => {
3292
- const result = await host.simulation.getAvailableRecipesAsync({
3293
- roomId,
3294
- includeActorRecipes
3295
- });
3296
- return result.recipes;
3188
+ venusApi.simulation.getAvailableRecipesAsync = async (options) => {
3189
+ return host.simulation.getAvailableRecipesAsync(options);
3297
3190
  };
3298
- venusApi.simulation.getRecipeRequirementsAsync = (recipeId, entity, amount) => {
3299
- return host.simulation.getRecipeRequirementsAsync({
3300
- recipeId,
3301
- entity,
3302
- batchAmount: amount
3303
- });
3191
+ venusApi.simulation.getRecipeRequirementsAsync = (recipe) => {
3192
+ return host.simulation.getRecipeRequirementsAsync(recipe);
3304
3193
  };
3305
3194
  venusApi.simulation.getBatchRecipeRequirementsAsync = (recipes) => {
3306
3195
  return host.simulation.getBatchRecipeRequirementsAsync(recipes);
@@ -3343,9 +3232,6 @@ function initializeSimulation(venusApi, host) {
3343
3232
  itemId
3344
3233
  );
3345
3234
  };
3346
- venusApi.simulation.sumContributions = (contributions) => {
3347
- return host.simulation.sumContributions(contributions);
3348
- };
3349
3235
  }
3350
3236
 
3351
3237
  // src/time/utils.ts
@@ -3364,9 +3250,11 @@ function isPacificDaylightTime(date) {
3364
3250
 
3365
3251
  // src/time/HostTimeApi.ts
3366
3252
  var HostTimeApi = class {
3367
- constructor(rpcClient) {
3253
+ constructor(rpcClient, venusApi) {
3368
3254
  __publicField(this, "rpcClient");
3255
+ __publicField(this, "venusApi");
3369
3256
  this.rpcClient = rpcClient;
3257
+ this.venusApi = venusApi;
3370
3258
  }
3371
3259
  async requestTimeAsync() {
3372
3260
  const response = await this.rpcClient.call(
@@ -3376,13 +3264,7 @@ var HostTimeApi = class {
3376
3264
  return response;
3377
3265
  }
3378
3266
  formatTime(timestamp, options) {
3379
- let locale = "en-US";
3380
- const windowVenus = window.venus;
3381
- if (windowVenus._config.locale) {
3382
- locale = windowVenus._config.locale;
3383
- } else if (windowVenus._config.environment && windowVenus._config.environment.browserInfo && windowVenus._config.environment.browserInfo.language) {
3384
- locale = windowVenus._config.environment.browserInfo.language;
3385
- }
3267
+ const locale = this.venusApi.getLocale();
3386
3268
  const date = new Date(timestamp);
3387
3269
  const dateTimeOptions = {
3388
3270
  dateStyle: options.dateStyle || "medium",
@@ -3394,13 +3276,7 @@ var HostTimeApi = class {
3394
3276
  }
3395
3277
  formatNumber(value, options) {
3396
3278
  try {
3397
- let locale = "en-US";
3398
- const windowVenus = window.venus;
3399
- if (windowVenus._config.locale) {
3400
- locale = windowVenus._config.locale;
3401
- } else if (windowVenus._config.environment && windowVenus._config.environment.browserInfo && windowVenus._config.environment.browserInfo.language) {
3402
- locale = windowVenus._config.environment.browserInfo.language;
3403
- }
3279
+ const locale = this.venusApi.getLocale();
3404
3280
  const numberOptions = {
3405
3281
  style: options?.style || "decimal",
3406
3282
  minimumFractionDigits: options?.minimumFractionDigits || 0,
@@ -3463,18 +3339,17 @@ var MockTimeApi = class {
3463
3339
  this.venusApi = venusApi;
3464
3340
  }
3465
3341
  formatNumber(value, options) {
3466
- const locale = this.getLocale();
3342
+ const locale = this.venusApi.getLocale();
3467
3343
  const numberOptions = {
3468
3344
  style: options?.style || "decimal",
3469
3345
  minimumFractionDigits: options?.minimumFractionDigits || 0,
3470
3346
  maximumFractionDigits: options?.maximumFractionDigits || 2,
3471
3347
  ...options
3472
3348
  };
3473
- console.log(`[Venus Mock] Formatting number ${value} with locale ${locale}`);
3474
3349
  return value.toLocaleString(locale, numberOptions);
3475
3350
  }
3476
3351
  formatTime(timestamp, options) {
3477
- const locale = this.getLocale();
3352
+ const locale = this.venusApi.getLocale();
3478
3353
  const date = new Date(timestamp);
3479
3354
  const dateTimeOptions = {
3480
3355
  dateStyle: options.dateStyle || "medium",
@@ -3482,13 +3357,9 @@ var MockTimeApi = class {
3482
3357
  hour12: options.hour12 !== void 0 ? options.hour12 : true,
3483
3358
  ...options
3484
3359
  };
3485
- console.log(
3486
- `[Venus Mock] Formatting time ${timestamp} with locale ${locale}`
3487
- );
3488
3360
  return date.toLocaleString(locale, dateTimeOptions);
3489
3361
  }
3490
3362
  async getFutureTimeAsync(options) {
3491
- console.log("[Venus Mock] Getting future time with options:", options);
3492
3363
  const timeInfo = await this.requestTimeAsync();
3493
3364
  const serverTime = new Date(timeInfo.serverTime);
3494
3365
  const result = new Date(serverTime);
@@ -3533,7 +3404,6 @@ var MockTimeApi = class {
3533
3404
  return result.getTime();
3534
3405
  }
3535
3406
  async requestTimeAsync() {
3536
- console.log("[Venus Mock] Requesting time");
3537
3407
  await createMockDelay(MOCK_DELAYS.short);
3538
3408
  const venusApi = this.venusApi;
3539
3409
  const mockOffset = venusApi._mock.serverTimeOffset || 2500;
@@ -3547,23 +3417,8 @@ var MockTimeApi = class {
3547
3417
  formattedTime: new Date(localTime).toISOString(),
3548
3418
  locale: venusApi._mock.user?.locale || "en-US"
3549
3419
  };
3550
- console.log("[Venus Mock] Time response:", {
3551
- serverTime: new Date(timeInfo.serverTime).toISOString(),
3552
- localTime: new Date(timeInfo.localTime).toISOString(),
3553
- timezoneOffset: timeInfo.timezoneOffset
3554
- });
3555
3420
  return timeInfo;
3556
3421
  }
3557
- getLocale() {
3558
- const venusApi = this.venusApi;
3559
- let locale = "en-US";
3560
- if (venusApi._mock.user && venusApi._mock.user.locale) {
3561
- locale = venusApi._mock.user.locale;
3562
- } else if (venusApi._mock.environment && venusApi._mock.environment.browserInfo.language) {
3563
- locale = venusApi._mock.environment.browserInfo.language;
3564
- }
3565
- return locale;
3566
- }
3567
3422
  };
3568
3423
 
3569
3424
  // src/time/index.ts
@@ -3583,11 +3438,176 @@ function initializeTime(venusApi, host) {
3583
3438
  }
3584
3439
 
3585
3440
  // src/version.ts
3586
- var SDK_VERSION = "3.0.4";
3441
+ var SDK_VERSION = "3.2.0";
3442
+
3443
+ // src/shared-assets/embeddedLibrariesManifest.ts
3444
+ var DEFAULT_SHARED_LIB_CDN_BASE = "https://venus-static-01293ak.web.app/libs";
3445
+ var EMBEDDED_LIBRARIES = [
3446
+ {
3447
+ libraryKey: "phaser@3.90.0",
3448
+ assetKey: "library:phaser@3.90.0",
3449
+ packageName: "phaser",
3450
+ version: "3.90.0",
3451
+ globalVar: "Phaser",
3452
+ cdnPath: "phaser/3.90.0/phaser.min.js",
3453
+ moduleSpecifiers: [{ match: "exact", value: "phaser" }],
3454
+ loadStage: 0,
3455
+ enabled: true
3456
+ },
3457
+ {
3458
+ libraryKey: "react@18.3.1",
3459
+ assetKey: "library:react@18.3.1",
3460
+ packageName: "react",
3461
+ version: "18.3.1",
3462
+ globalVar: "React",
3463
+ cdnPath: "react/18.3.1/react.production.min.js",
3464
+ moduleSpecifiers: [
3465
+ { match: "exact", value: "react", behavior: "namespace" },
3466
+ { match: "exact", value: "react/jsx-runtime", behavior: "react-jsx-runtime" },
3467
+ {
3468
+ match: "exact",
3469
+ value: "react/jsx-dev-runtime",
3470
+ behavior: "react-jsx-dev-runtime"
3471
+ }
3472
+ ],
3473
+ loadStage: 0,
3474
+ // Must load before ReactDOM
3475
+ enabled: true
3476
+ },
3477
+ {
3478
+ libraryKey: "react-dom@18.3.1",
3479
+ assetKey: "library:react-dom@18.3.1",
3480
+ packageName: "react-dom",
3481
+ version: "18.3.1",
3482
+ globalVar: "ReactDOM",
3483
+ cdnPath: "react-dom/18.3.1/react-dom.production.min.js",
3484
+ moduleSpecifiers: [
3485
+ { match: "exact", value: "react-dom", behavior: "namespace" },
3486
+ { match: "exact", value: "react-dom/client", behavior: "namespace" }
3487
+ ],
3488
+ loadStage: 1,
3489
+ // Depends on React (stage 0)
3490
+ enabled: true
3491
+ },
3492
+ {
3493
+ libraryKey: "three@0.170.0",
3494
+ assetKey: "library:three@0.170.0",
3495
+ packageName: "three",
3496
+ version: "0.170.0",
3497
+ globalVar: "THREE",
3498
+ cdnPath: "three/r170/three.min.js",
3499
+ moduleSpecifiers: [
3500
+ { match: "exact", value: "three", behavior: "namespace" },
3501
+ { match: "prefix", value: "three/examples/jsm/", behavior: "namespace" }
3502
+ ],
3503
+ loadStage: 0,
3504
+ enabled: true
3505
+ },
3506
+ {
3507
+ libraryKey: "matter-js@0.19.0",
3508
+ assetKey: "library:matter-js@0.19.0",
3509
+ packageName: "matter-js",
3510
+ version: "0.19.0",
3511
+ globalVar: "Matter",
3512
+ cdnPath: "matter-js/0.19.0/matter.min.js",
3513
+ moduleSpecifiers: [{ match: "exact", value: "matter-js" }],
3514
+ loadStage: 0,
3515
+ enabled: true
3516
+ },
3517
+ {
3518
+ libraryKey: "inkjs@2.2.0",
3519
+ assetKey: "library:inkjs@2.2.0",
3520
+ packageName: "inkjs",
3521
+ version: "2.2.0",
3522
+ globalVar: "inkjs",
3523
+ cdnPath: "inkjs/2.2.0/ink.min.js",
3524
+ moduleSpecifiers: [{ match: "exact", value: "inkjs" }],
3525
+ loadStage: 0,
3526
+ enabled: true
3527
+ },
3528
+ {
3529
+ libraryKey: "zustand@5.0.3",
3530
+ assetKey: "library:zustand@5.0.3",
3531
+ packageName: "zustand",
3532
+ version: "5.0.3",
3533
+ globalVar: "zustand",
3534
+ cdnPath: "zustand/5.0.3/zustand.min.js",
3535
+ moduleSpecifiers: [
3536
+ { match: "exact", value: "zustand" },
3537
+ { match: "exact", value: "zustand/middleware" }
3538
+ ],
3539
+ loadStage: 0,
3540
+ enabled: true
3541
+ },
3542
+ {
3543
+ libraryKey: "ammo.js@2024.11",
3544
+ assetKey: "library:ammo.js@2024.11",
3545
+ packageName: "ammo.js",
3546
+ version: "2024.11",
3547
+ globalVar: "Ammo",
3548
+ cdnPath: "ammo/2024.11/ammo.js",
3549
+ moduleSpecifiers: [
3550
+ { match: "exact", value: "ammo.js" },
3551
+ { match: "exact", value: "ammo.js/builds/ammo.wasm.js" }
3552
+ ],
3553
+ loadStage: 0,
3554
+ enabled: false
3555
+ // Not ready yet - WASM loading needs additional work
3556
+ }
3557
+ ];
3558
+ var EMBEDDED_LIBRARY_BY_KEY = EMBEDDED_LIBRARIES.reduce(
3559
+ (acc, lib) => {
3560
+ acc[lib.libraryKey] = lib;
3561
+ return acc;
3562
+ },
3563
+ {}
3564
+ );
3565
+ var MODULE_TO_LIBRARY_SPECIFIERS = EMBEDDED_LIBRARIES.filter(
3566
+ (lib) => lib.enabled
3567
+ ).flatMap(
3568
+ (lib) => lib.moduleSpecifiers.map((specifier) => ({
3569
+ ...specifier,
3570
+ libraryKey: lib.libraryKey
3571
+ }))
3572
+ );
3573
+ function getLibraryDefinition(libraryKey) {
3574
+ const definition = EMBEDDED_LIBRARY_BY_KEY[libraryKey];
3575
+ if (!definition) {
3576
+ const availableKeys = Object.keys(EMBEDDED_LIBRARY_BY_KEY).join(", ");
3577
+ throw new Error(
3578
+ `Unsupported embedded library: ${libraryKey}. Available libraries: ${availableKeys}`
3579
+ );
3580
+ }
3581
+ return definition;
3582
+ }
3587
3583
 
3588
- // src/shared-assets/consts.ts
3589
- var BurgerTimeAssetsCdnPath = "burger-time/Core.stow";
3590
- var CharacterAssetsCdnPath = "burger-time/Character.stow";
3584
+ // src/shared-assets/base64Utils.ts
3585
+ function base64ToArrayBuffer(base64) {
3586
+ const binaryString = atob(base64);
3587
+ const len = binaryString.length;
3588
+ const bytes = new Uint8Array(len);
3589
+ for (let i = 0; i < len; i++) {
3590
+ bytes[i] = binaryString.charCodeAt(i);
3591
+ }
3592
+ return bytes.buffer;
3593
+ }
3594
+ function base64ToUtf8(base64) {
3595
+ if (typeof TextDecoder !== "undefined") {
3596
+ const decoder = new TextDecoder("utf-8");
3597
+ const buffer = base64ToArrayBuffer(base64);
3598
+ return decoder.decode(new Uint8Array(buffer));
3599
+ }
3600
+ if (typeof globalThis !== "undefined" && typeof globalThis.Buffer !== "undefined") {
3601
+ const BufferCtor = globalThis.Buffer;
3602
+ return BufferCtor.from(base64, "base64").toString("utf-8");
3603
+ }
3604
+ const binaryString = atob(base64);
3605
+ let result = "";
3606
+ for (let i = 0; i < binaryString.length; i++) {
3607
+ result += String.fromCharCode(binaryString.charCodeAt(i));
3608
+ }
3609
+ return decodeURIComponent(escape(result));
3610
+ }
3591
3611
 
3592
3612
  // src/shared-assets/RpcSharedAssetsApi.ts
3593
3613
  var RpcSharedAssetsApi = class {
@@ -3597,46 +3617,48 @@ var RpcSharedAssetsApi = class {
3597
3617
  this.rpcClient = rpcClient;
3598
3618
  this.venusApi = venusApi;
3599
3619
  }
3600
- async loadBurgerTimeAssetsBundle() {
3620
+ async loadAssetsBundle(game, bundleKey, fileType = "stow") {
3601
3621
  try {
3602
3622
  const response = await this.rpcClient.callT("H5_LOAD_EMBEDDED_ASSET" /* H5_LOAD_EMBEDDED_ASSET */, {
3603
- assetKey: "burgerTimeCoreBundle"
3623
+ assetKey: bundleKey
3604
3624
  });
3605
3625
  return base64ToArrayBuffer(response.base64Data);
3606
3626
  } catch (err) {
3607
3627
  try {
3608
- const blob = await this.venusApi.cdn.fetchBlob(BurgerTimeAssetsCdnPath);
3628
+ const blob = await this.venusApi.cdn.fetchBlob(`${game}/${bundleKey}.${fileType}`);
3609
3629
  return await blob.arrayBuffer();
3610
3630
  } catch (e) {
3611
- throw new Error("Failed to load burgerTimeAssetsBundle");
3631
+ throw new Error(`Failed to load ${bundleKey}`);
3612
3632
  }
3613
3633
  }
3614
3634
  }
3615
- async loadCharactersBundle() {
3635
+ async loadLibraryCode(libraryKey) {
3636
+ const definition = getLibraryDefinition(libraryKey);
3616
3637
  try {
3617
3638
  const response = await this.rpcClient.callT("H5_LOAD_EMBEDDED_ASSET" /* H5_LOAD_EMBEDDED_ASSET */, {
3618
- assetKey: "characters"
3639
+ assetKey: definition.assetKey
3619
3640
  });
3620
- return base64ToArrayBuffer(response.base64Data);
3641
+ return base64ToUtf8(response.base64Data);
3621
3642
  } catch (err) {
3643
+ console.error(
3644
+ `[Venus Libraries] Failed to load ${libraryKey} from host via RPC:`,
3645
+ err
3646
+ );
3647
+ console.warn(
3648
+ `[Venus Libraries] Falling back to CDN for ${libraryKey}. This may indicate an asset packaging issue.`
3649
+ );
3622
3650
  try {
3623
- const blob = await this.venusApi.cdn.fetchBlob(CharacterAssetsCdnPath);
3624
- return await blob.arrayBuffer();
3625
- } catch (e) {
3626
- throw new Error("Failed to load charactersBundle");
3651
+ const cdnUrl = this.venusApi.cdn.resolveSharedLibUrl(definition.cdnPath);
3652
+ const response = await this.venusApi.cdn.fetchFromCdn(cdnUrl);
3653
+ return await response.text();
3654
+ } catch (cdnError) {
3655
+ throw new Error(
3656
+ `Failed to load embedded library ${libraryKey}: RPC failed, CDN fallback failed: ${cdnError.message}`
3657
+ );
3627
3658
  }
3628
3659
  }
3629
3660
  }
3630
3661
  };
3631
- function base64ToArrayBuffer(base64) {
3632
- const binaryString = atob(base64);
3633
- const len = binaryString.length;
3634
- const bytes = new Uint8Array(len);
3635
- for (let i = 0; i < len; i++) {
3636
- bytes[i] = binaryString.charCodeAt(i);
3637
- }
3638
- return bytes.buffer;
3639
- }
3640
3662
 
3641
3663
  // src/shared-assets/MockSharedAssetsApi.ts
3642
3664
  var MockSharedAssetsApi = class {
@@ -3644,57 +3666,118 @@ var MockSharedAssetsApi = class {
3644
3666
  __publicField(this, "venusApi");
3645
3667
  this.venusApi = venusApi;
3646
3668
  }
3647
- async loadBurgerTimeAssetsBundle() {
3648
- const blob = await this.venusApi.cdn.fetchBlob(BurgerTimeAssetsCdnPath);
3669
+ async loadAssetsBundle(game, bundleKey, fileType = "stow") {
3670
+ const blob = await this.venusApi.cdn.fetchBlob(`${game}/${bundleKey}.${fileType}`);
3649
3671
  return await blob.arrayBuffer();
3650
3672
  }
3651
- async loadCharactersBundle() {
3652
- const blob = await this.venusApi.cdn.fetchBlob(CharacterAssetsCdnPath);
3653
- return await blob.arrayBuffer();
3673
+ async loadLibraryCode(libraryKey) {
3674
+ const definition = getLibraryDefinition(libraryKey);
3675
+ const url = this.venusApi.cdn.resolveSharedLibUrl(definition.cdnPath);
3676
+ const response = await this.venusApi.cdn.fetchFromCdn(url);
3677
+ return await response.text();
3654
3678
  }
3655
3679
  };
3656
3680
 
3681
+ // src/leaderboard/utils.ts
3682
+ var HASH_ALGORITHM_WEB_CRYPTO = "SHA-256";
3683
+ var HASH_ALGORITHM_NODE = "sha256";
3684
+ async function computeScoreHash(score, duration, token, sealingNonce, sealingSecret) {
3685
+ const payload = `score:${score}|duration:${duration}|token:${token}`;
3686
+ const fullPayload = `${payload}|nonce:${sealingNonce}`;
3687
+ const encoder = new TextEncoder();
3688
+ const keyData = encoder.encode(sealingSecret);
3689
+ const messageData = encoder.encode(fullPayload);
3690
+ const cryptoKey = await crypto.subtle.importKey(
3691
+ "raw",
3692
+ keyData,
3693
+ { name: "HMAC", hash: HASH_ALGORITHM_WEB_CRYPTO },
3694
+ false,
3695
+ ["sign"]
3696
+ );
3697
+ const signature = await crypto.subtle.sign("HMAC", cryptoKey, messageData);
3698
+ return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
3699
+ }
3700
+
3657
3701
  // src/leaderboard/RpcLeaderboardApi.ts
3658
3702
  var RpcLeaderboardApi = class {
3659
3703
  constructor(rpcClient) {
3660
3704
  __publicField(this, "rpcClient");
3705
+ /** Cache of score tokens for automatic hash computation */
3706
+ __publicField(this, "tokenCache", /* @__PURE__ */ new Map());
3661
3707
  this.rpcClient = rpcClient;
3662
3708
  }
3663
- startRun(mode) {
3664
- return this.rpcClient.call(
3665
- "H5_LEADERBOARD_START_RUN" /* H5_LEADERBOARD_START_RUN */,
3709
+ /**
3710
+ * Create a score token for submitting a score.
3711
+ * Token is cached for automatic hash computation if score sealing is enabled.
3712
+ *
3713
+ * @param mode - Optional game mode
3714
+ * @returns Score token with sealing data if enabled
3715
+ */
3716
+ async createScoreToken(mode) {
3717
+ const token = await this.rpcClient.call(
3718
+ "H5_LEADERBOARD_CREATE_SCORE_TOKEN" /* H5_LEADERBOARD_CREATE_SCORE_TOKEN */,
3666
3719
  mode ? { mode } : {}
3667
3720
  );
3721
+ this.tokenCache.set(token.token, token);
3722
+ return token;
3668
3723
  }
3669
- submitScore(sessionId, score, durationSec, options) {
3724
+ /**
3725
+ * Submit a score to the leaderboard.
3726
+ * Automatically computes hash if score sealing is enabled and token was created via createScoreToken().
3727
+ *
3728
+ * @param params - Score submission parameters
3729
+ * @returns Submission result with acceptance status and rank
3730
+ * @throws Error if token not found in cache
3731
+ */
3732
+ async submitScore(params) {
3733
+ let hash;
3734
+ if (params.token) {
3735
+ const cachedToken = this.tokenCache.get(params.token);
3736
+ if (!cachedToken) {
3737
+ throw new Error(
3738
+ "Invalid token: not found in cache. Did you call createScoreToken() first?"
3739
+ );
3740
+ }
3741
+ if (cachedToken.sealingNonce && cachedToken.sealingSecret) {
3742
+ hash = await computeScoreHash(
3743
+ params.score,
3744
+ params.duration,
3745
+ params.token,
3746
+ cachedToken.sealingNonce,
3747
+ cachedToken.sealingSecret
3748
+ );
3749
+ }
3750
+ this.tokenCache.delete(params.token);
3751
+ }
3670
3752
  return this.rpcClient.call(
3671
3753
  "H5_LEADERBOARD_SUBMIT_SCORE" /* H5_LEADERBOARD_SUBMIT_SCORE */,
3672
3754
  {
3673
- sessionId,
3674
- score,
3675
- durationSec,
3676
- mode: options?.mode,
3677
- telemetry: options?.telemetry,
3678
- metadata: options?.metadata,
3679
- hash: options?.hash
3755
+ token: params.token,
3756
+ score: params.score,
3757
+ duration: params.duration,
3758
+ mode: params.mode,
3759
+ telemetry: params.telemetry,
3760
+ metadata: params.metadata,
3761
+ hash
3762
+ // undefined if no sealing, computed if sealing enabled
3680
3763
  }
3681
3764
  );
3682
3765
  }
3683
- getLeaderboard(options) {
3766
+ getPagedScores(options) {
3684
3767
  return this.rpcClient.call(
3685
- "H5_LEADERBOARD_GET" /* H5_LEADERBOARD_GET */,
3768
+ "H5_LEADERBOARD_GET_PAGED_SCORES" /* H5_LEADERBOARD_GET_PAGED_SCORES */,
3686
3769
  options ?? {}
3687
3770
  );
3688
3771
  }
3689
- getPlayerStats(options) {
3772
+ getMyRank(options) {
3690
3773
  return this.rpcClient.call(
3691
- "H5_LEADERBOARD_GET_PLAYER_STATS" /* H5_LEADERBOARD_GET_PLAYER_STATS */,
3774
+ "H5_LEADERBOARD_GET_MY_RANK" /* H5_LEADERBOARD_GET_MY_RANK */,
3692
3775
  options ?? {}
3693
3776
  );
3694
3777
  }
3695
- getLeaderboardHighlight(options) {
3778
+ getPodiumScores(options) {
3696
3779
  return this.rpcClient.call(
3697
- "H5_LEADERBOARD_GET_HIGHLIGHT" /* H5_LEADERBOARD_GET_HIGHLIGHT */,
3780
+ "H5_LEADERBOARD_GET_PODIUM_SCORES" /* H5_LEADERBOARD_GET_PODIUM_SCORES */,
3698
3781
  options ?? {}
3699
3782
  );
3700
3783
  }
@@ -3703,17 +3786,31 @@ var RpcLeaderboardApi = class {
3703
3786
  // src/leaderboard/MockLeaderboardApi.ts
3704
3787
  var MockLeaderboardApi = class {
3705
3788
  constructor(options) {
3706
- __publicField(this, "sessions", /* @__PURE__ */ new Map());
3789
+ __publicField(this, "tokens", /* @__PURE__ */ new Map());
3790
+ /** Cache of score tokens for automatic hash computation */
3791
+ __publicField(this, "tokenCache", /* @__PURE__ */ new Map());
3707
3792
  __publicField(this, "entriesByMode", /* @__PURE__ */ new Map());
3708
- __publicField(this, "sessionCounter", 0);
3709
- __publicField(this, "requiresHash", false);
3710
- if (options?.requiresHash) {
3711
- this.requiresHash = true;
3793
+ __publicField(this, "tokenCounter", 0);
3794
+ __publicField(this, "enableScoreSealing", false);
3795
+ __publicField(this, "scoreSealingSecret", "mock-leaderboard-secret-key");
3796
+ if (options?.enableScoreSealing) {
3797
+ this.enableScoreSealing = true;
3798
+ }
3799
+ if (options?.scoreSealingSecret) {
3800
+ this.scoreSealingSecret = options.scoreSealingSecret;
3712
3801
  }
3713
3802
  }
3803
+ /**
3804
+ * Configure mock leaderboard settings
3805
+ *
3806
+ * @param options - Configuration options
3807
+ */
3714
3808
  configure(options) {
3715
- if (typeof options.requiresHash === "boolean") {
3716
- this.requiresHash = options.requiresHash;
3809
+ if (typeof options.enableScoreSealing === "boolean") {
3810
+ this.enableScoreSealing = options.enableScoreSealing;
3811
+ }
3812
+ if (options.scoreSealingSecret) {
3813
+ this.scoreSealingSecret = options.scoreSealingSecret;
3717
3814
  }
3718
3815
  }
3719
3816
  generateNonce() {
@@ -3730,83 +3827,149 @@ var MockLeaderboardApi = class {
3730
3827
  }
3731
3828
  return this.entriesByMode.get(key);
3732
3829
  }
3733
- async startRun(mode) {
3734
- const sessionId = `mock_session_${++this.sessionCounter}`;
3830
+ /**
3831
+ * Create a mock score token for testing.
3832
+ * Token is cached for automatic hash computation if score sealing is enabled.
3833
+ *
3834
+ * @param mode - Optional game mode
3835
+ * @returns Score token with sealing data if enabled
3836
+ */
3837
+ async createScoreToken(mode) {
3838
+ const token = `mock_token_${++this.tokenCounter}`;
3735
3839
  const startTime = Date.now();
3736
3840
  const expiresAt = startTime + 36e5;
3737
3841
  const resolvedMode = mode || "default";
3738
- const hashNonce = this.requiresHash ? this.generateNonce() : null;
3739
- this.sessions.set(sessionId, {
3740
- id: sessionId,
3842
+ const sealingNonce = this.enableScoreSealing ? this.generateNonce() : null;
3843
+ const sealingSecret = this.enableScoreSealing ? this.scoreSealingSecret : null;
3844
+ this.tokens.set(token, {
3845
+ id: token,
3741
3846
  expiresAt,
3742
3847
  mode: resolvedMode,
3743
- hashNonce,
3848
+ sealingNonce,
3744
3849
  used: false
3745
3850
  });
3746
- return {
3747
- sessionId,
3851
+ const result = {
3852
+ token,
3748
3853
  startTime,
3749
3854
  expiresAt,
3750
- hashNonce,
3855
+ sealingNonce,
3856
+ sealingSecret,
3751
3857
  mode: resolvedMode
3752
3858
  };
3859
+ this.tokenCache.set(token, result);
3860
+ return result;
3753
3861
  }
3754
- async submitScore(sessionId, score, durationSec, options) {
3755
- const session = this.sessions.get(sessionId);
3756
- if (!session) {
3757
- throw new Error("Invalid leaderboard session");
3862
+ /**
3863
+ * Submit a mock score to the leaderboard.
3864
+ * Automatically computes hash if score sealing is enabled and token was created via createScoreToken().
3865
+ *
3866
+ * @param params - Score submission parameters
3867
+ * @returns Submission result with acceptance status and rank
3868
+ * @throws Error if token not found in cache or validation fails
3869
+ */
3870
+ async submitScore(params) {
3871
+ let hash;
3872
+ if (params.token) {
3873
+ const cachedToken = this.tokenCache.get(params.token);
3874
+ if (!cachedToken) {
3875
+ throw new Error(
3876
+ "Invalid token: not found in cache. Did you call createScoreToken() first?"
3877
+ );
3878
+ }
3879
+ if (cachedToken.sealingNonce && cachedToken.sealingSecret) {
3880
+ hash = await computeScoreHash(
3881
+ params.score,
3882
+ params.duration,
3883
+ params.token,
3884
+ cachedToken.sealingNonce,
3885
+ cachedToken.sealingSecret
3886
+ );
3887
+ }
3888
+ }
3889
+ if (!params.token) {
3890
+ const mode = params.mode || "default";
3891
+ const submittedAt2 = Date.now();
3892
+ const entry2 = {
3893
+ profileId: `mock_profile`,
3894
+ username: "Mock Player",
3895
+ avatarUrl: null,
3896
+ score: params.score,
3897
+ duration: params.duration,
3898
+ submittedAt: submittedAt2,
3899
+ token: "simple-mode",
3900
+ rank: null,
3901
+ zScore: null,
3902
+ isAnomaly: false,
3903
+ trustScore: 50,
3904
+ metadata: params.metadata ?? null,
3905
+ isSeed: false
3906
+ };
3907
+ const modeEntries2 = this.getEntriesForMode(mode);
3908
+ modeEntries2.push(entry2);
3909
+ modeEntries2.sort((a, b) => {
3910
+ if (b.score !== a.score) return b.score - a.score;
3911
+ return a.submittedAt - b.submittedAt;
3912
+ });
3913
+ modeEntries2.forEach((e, index) => {
3914
+ modeEntries2[index] = { ...e, rank: index + 1 };
3915
+ });
3916
+ const inserted2 = modeEntries2.find((e) => e.submittedAt === submittedAt2);
3917
+ return {
3918
+ accepted: true,
3919
+ rank: inserted2?.rank ?? null
3920
+ };
3921
+ }
3922
+ const scoreToken = this.tokens.get(params.token);
3923
+ if (!scoreToken) {
3924
+ throw new Error("Invalid score token");
3758
3925
  }
3759
- if (session.expiresAt < Date.now()) {
3760
- throw new Error("Invalid or expired leaderboard session");
3926
+ if (scoreToken.expiresAt < Date.now()) {
3927
+ throw new Error("Invalid or expired score token");
3761
3928
  }
3762
- if (session.used) {
3763
- throw new Error("Leaderboard session already used");
3929
+ if (scoreToken.used) {
3930
+ throw new Error("Score token already used");
3764
3931
  }
3765
- if (options?.mode && options.mode !== session.mode) {
3766
- throw new Error("Submission mode does not match session mode");
3932
+ if (params.mode && params.mode !== scoreToken.mode) {
3933
+ throw new Error("Submission mode does not match token mode");
3767
3934
  }
3768
- if (session.hashNonce && !options?.hash) {
3769
- throw new Error("Score hash is required for sealed leaderboard submissions");
3935
+ if (scoreToken.sealingNonce && !hash) {
3936
+ throw new Error("Score hash required when score sealing is enabled");
3770
3937
  }
3771
3938
  const submittedAt = Date.now();
3772
3939
  const entry = {
3773
3940
  profileId: `mock_profile`,
3774
3941
  username: "Mock Player",
3775
3942
  avatarUrl: null,
3776
- score,
3777
- durationSec,
3943
+ score: params.score,
3944
+ duration: params.duration,
3778
3945
  submittedAt,
3779
- sessionId,
3946
+ token: params.token,
3780
3947
  rank: null,
3781
3948
  zScore: null,
3782
3949
  isAnomaly: false,
3783
3950
  trustScore: 50,
3784
- metadata: options?.metadata ?? null,
3951
+ metadata: params.metadata ?? null,
3785
3952
  isSeed: false
3786
3953
  };
3787
- const modeEntries = this.getEntriesForMode(session.mode);
3954
+ const modeEntries = this.getEntriesForMode(scoreToken.mode);
3788
3955
  modeEntries.push(entry);
3789
3956
  modeEntries.sort((a, b) => {
3790
- if (b.score !== a.score) {
3791
- return b.score - a.score;
3792
- }
3957
+ if (b.score !== a.score) return b.score - a.score;
3793
3958
  return a.submittedAt - b.submittedAt;
3794
3959
  });
3795
3960
  modeEntries.forEach((e, index) => {
3796
- modeEntries[index] = {
3797
- ...e,
3798
- rank: index + 1
3799
- };
3961
+ modeEntries[index] = { ...e, rank: index + 1 };
3800
3962
  });
3801
- session.used = true;
3802
- session.hashNonce = null;
3803
- const inserted = modeEntries.find((e) => e.sessionId === sessionId && e.submittedAt === submittedAt);
3963
+ scoreToken.used = true;
3964
+ scoreToken.sealingNonce = null;
3965
+ this.tokenCache.delete(params.token);
3966
+ const inserted = modeEntries.find((e) => e.token === params.token && e.submittedAt === submittedAt);
3804
3967
  return {
3805
3968
  accepted: true,
3806
3969
  rank: inserted?.rank ?? null
3807
3970
  };
3808
3971
  }
3809
- async getLeaderboard(options) {
3972
+ async getPagedScores(options) {
3810
3973
  const limit = options?.limit ?? 10;
3811
3974
  const mode = options?.mode ?? "default";
3812
3975
  const modeEntries = [...this.getEntriesForMode(mode)];
@@ -3822,7 +3985,7 @@ var MockLeaderboardApi = class {
3822
3985
  periodInstance: options?.period ?? "alltime"
3823
3986
  };
3824
3987
  }
3825
- async getPlayerStats(_options) {
3988
+ async getMyRank(_options) {
3826
3989
  const mode = _options?.mode ?? "default";
3827
3990
  const modeEntries = this.getEntriesForMode(mode);
3828
3991
  const playerEntry = modeEntries[0] ?? null;
@@ -3835,7 +3998,7 @@ var MockLeaderboardApi = class {
3835
3998
  periodInstance: _options?.period ?? "alltime"
3836
3999
  };
3837
4000
  }
3838
- async getLeaderboardHighlight(options) {
4001
+ async getPodiumScores(options) {
3839
4002
  const mode = options?.mode ?? "default";
3840
4003
  const modeEntries = [...this.getEntriesForMode(mode)];
3841
4004
  const topCount = Math.max(1, Math.min(options?.topCount ?? 3, 10));
@@ -3903,105 +4066,29 @@ var MockPreloaderApi = class {
3903
4066
  };
3904
4067
 
3905
4068
  // src/game-preloader/RpcPreloaderApi.ts
3906
- var RpcPreloaderApi = class {
3907
- constructor(rpcClient) {
3908
- __publicField(this, "rpcClient");
3909
- this.rpcClient = rpcClient;
3910
- }
3911
- async showLoadScreen() {
3912
- await this.rpcClient.call("H5_SHOW_LOAD_SCREEN" /* H5_SHOW_LOAD_SCREEN */);
3913
- }
3914
- async hideLoadScreen() {
3915
- await this.rpcClient.call("H5_HIDE_LOAD_SCREEN" /* H5_HIDE_LOAD_SCREEN */);
3916
- }
3917
- async setLoaderText(text) {
3918
- await this.rpcClient.call("H5_SET_LOADER_TEXT" /* H5_SET_LOADER_TEXT */, { text });
3919
- }
3920
- async setLoaderProgress(progress) {
3921
- await this.rpcClient.call("H5_SET_LOADER_PROGRESS" /* H5_SET_LOADER_PROGRESS */, { progress });
3922
- }
3923
- };
3924
-
3925
- // src/game-preloader/index.ts
3926
- function initializePreloader(venusApi, host) {
3927
- venusApi.preloader = host.preloader;
3928
- }
3929
-
3930
- // src/post/MockPostApi.ts
3931
- var MockPostApi = class {
3932
- constructor(venusApi) {
3933
- __publicField(this, "venusApi");
3934
- this.venusApi = venusApi;
3935
- }
3936
- async getPostInfo() {
3937
- const venusApi = this.venusApi;
3938
- await createMockDelay(MOCK_DELAYS.short);
3939
- return venusApi._mock.currentPostInteractions;
3940
- }
3941
- async openCommentsAsync() {
3942
- await createMockDelay(MOCK_DELAYS.short);
3943
- return {
3944
- opened: true,
3945
- commentsCount: 0
3946
- };
3947
- }
3948
- async toggleFollowAsync() {
3949
- const venusApi = this.venusApi;
3950
- console.log("[Venus Mock] *Toggling follow status");
3951
- await createMockDelay(MOCK_DELAYS.short);
3952
- venusApi._mock.currentPostInteractions.isFollowing = !venusApi._mock.currentPostInteractions.isFollowing;
3953
- const isFollowing = venusApi._mock.currentPostInteractions.isFollowing;
3954
- return {
3955
- isFollowing,
3956
- action: isFollowing ? "followed" : "unfollowed"
3957
- };
3958
- }
3959
- async toggleLikeAsync() {
3960
- const venusApi = this.venusApi;
3961
- await createMockDelay(MOCK_DELAYS.short);
3962
- venusApi._mock.currentPostInteractions.isLiked = !venusApi._mock.currentPostInteractions.isLiked;
3963
- const isLiked = venusApi._mock.currentPostInteractions.isLiked;
3964
- if (isLiked) {
3965
- venusApi._mock.currentPostInteractions.likesCount++;
3966
- } else {
3967
- venusApi._mock.currentPostInteractions.likesCount = Math.max(
3968
- 0,
3969
- venusApi._mock.currentPostInteractions.likesCount - 1
3970
- );
3971
- }
3972
- return {
3973
- isLiked,
3974
- likesCount: venusApi._mock.currentPostInteractions.likesCount,
3975
- action: isLiked ? "liked" : "unliked"
3976
- };
3977
- }
3978
- };
3979
-
3980
- // src/post/RpcPostApi.ts
3981
- var RpcPostApi = class {
4069
+ var RpcPreloaderApi = class {
3982
4070
  constructor(rpcClient) {
3983
4071
  __publicField(this, "rpcClient");
3984
4072
  this.rpcClient = rpcClient;
3985
4073
  }
3986
- getPostInfo() {
3987
- return this.rpcClient.call("H5_GET_POST_INTERACTIONS" /* GET_POST_INTERACTIONS */, {});
4074
+ async showLoadScreen() {
4075
+ await this.rpcClient.call("H5_SHOW_LOAD_SCREEN" /* H5_SHOW_LOAD_SCREEN */);
3988
4076
  }
3989
- openCommentsAsync() {
3990
- return this.rpcClient.call("H5_OPEN_COMMENTS" /* OPEN_COMMENTS */, {});
4077
+ async hideLoadScreen() {
4078
+ await this.rpcClient.call("H5_HIDE_LOAD_SCREEN" /* H5_HIDE_LOAD_SCREEN */);
3991
4079
  }
3992
- toggleFollowAsync() {
3993
- return this.rpcClient.call(
3994
- "H5_TOGGLE_FOLLOW" /* TOGGLE_FOLLOW */,
3995
- {}
3996
- );
4080
+ async setLoaderText(text) {
4081
+ await this.rpcClient.call("H5_SET_LOADER_TEXT" /* H5_SET_LOADER_TEXT */, { text });
3997
4082
  }
3998
- toggleLikeAsync() {
3999
- return this.rpcClient.call("H5_TOGGLE_LIKE" /* TOGGLE_LIKE */, {});
4083
+ async setLoaderProgress(progress) {
4084
+ await this.rpcClient.call("H5_SET_LOADER_PROGRESS" /* H5_SET_LOADER_PROGRESS */, { progress });
4000
4085
  }
4001
4086
  };
4002
4087
 
4003
- // src/MockHost.ts
4004
- init_rooms();
4088
+ // src/game-preloader/index.ts
4089
+ function initializePreloader(venusApi, host) {
4090
+ venusApi.preloader = host.preloader;
4091
+ }
4005
4092
 
4006
4093
  // src/social/MockSocialApi.ts
4007
4094
  var MOCK_QR_CODE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
@@ -4039,44 +4126,116 @@ var ROOMS_UNAVAILABLE_MESSAGE = "[Venus SDK] Rooms API is only available when ru
4039
4126
  function createUnavailableRoomsApi() {
4040
4127
  const roomsUnavailableError = () => new Error(ROOMS_UNAVAILABLE_MESSAGE);
4041
4128
  return {
4042
- async createRoom() {
4129
+ async createRoomAsync() {
4043
4130
  throw roomsUnavailableError();
4044
4131
  },
4045
- async joinOrCreateRoom() {
4132
+ async joinOrCreateRoomAsync() {
4046
4133
  throw roomsUnavailableError();
4047
4134
  },
4048
- async getUserRooms() {
4135
+ async joinRoomByCodeAsync() {
4049
4136
  throw roomsUnavailableError();
4050
4137
  },
4051
- async joinRoomByCode() {
4138
+ async getUserRoomsAsync() {
4052
4139
  throw roomsUnavailableError();
4053
4140
  },
4054
- subscribe() {
4141
+ async subscribeAsync() {
4055
4142
  throw roomsUnavailableError();
4056
4143
  },
4057
- async updateData() {
4144
+ async updateRoomDataAsync() {
4058
4145
  throw roomsUnavailableError();
4059
4146
  },
4060
- async getData() {
4147
+ async getRoomDataAsync() {
4061
4148
  throw roomsUnavailableError();
4062
4149
  },
4063
- async sendMessage() {
4150
+ async sendRoomMessageAsync() {
4064
4151
  throw roomsUnavailableError();
4065
4152
  },
4066
- async leave() {
4153
+ async leaveRoomAsync() {
4067
4154
  throw roomsUnavailableError();
4068
4155
  },
4069
- async startGame() {
4156
+ async startRoomGameAsync() {
4070
4157
  throw roomsUnavailableError();
4071
4158
  },
4072
- async proposeMove() {
4159
+ async proposeMoveAsync() {
4073
4160
  throw roomsUnavailableError();
4074
4161
  },
4075
- async validateMove() {
4162
+ async validateMoveAsync() {
4076
4163
  throw roomsUnavailableError();
4077
4164
  }
4078
4165
  };
4079
4166
  }
4167
+ var SIMULATION_UNAVAILABLE_MESSAGE = "[Venus SDK] Simulation API is only available when running inside the Venus host environment.";
4168
+ function createUnavailableSimulationApi() {
4169
+ const simulationUnavailableError = () => new Error(SIMULATION_UNAVAILABLE_MESSAGE);
4170
+ return {
4171
+ isEnabled() {
4172
+ return false;
4173
+ },
4174
+ async getStateAsync() {
4175
+ throw simulationUnavailableError();
4176
+ },
4177
+ async getConfigAsync() {
4178
+ throw simulationUnavailableError();
4179
+ },
4180
+ async executeRecipeAsync() {
4181
+ throw simulationUnavailableError();
4182
+ },
4183
+ async getActiveRunsAsync() {
4184
+ throw simulationUnavailableError();
4185
+ },
4186
+ async collectRecipeAsync() {
4187
+ throw simulationUnavailableError();
4188
+ },
4189
+ async executeScopedRecipeAsync() {
4190
+ throw simulationUnavailableError();
4191
+ },
4192
+ async triggerRecipeChainAsync() {
4193
+ throw simulationUnavailableError();
4194
+ },
4195
+ async getAvailableRecipesAsync() {
4196
+ throw simulationUnavailableError();
4197
+ },
4198
+ async getRecipeRequirementsAsync() {
4199
+ throw simulationUnavailableError();
4200
+ },
4201
+ async getBatchRecipeRequirementsAsync() {
4202
+ throw simulationUnavailableError();
4203
+ },
4204
+ async resolveFieldValueAsync() {
4205
+ throw simulationUnavailableError();
4206
+ },
4207
+ async getEntityMetadataAsync() {
4208
+ throw simulationUnavailableError();
4209
+ },
4210
+ async getSlotContainersAsync() {
4211
+ throw simulationUnavailableError();
4212
+ },
4213
+ async getSlotAssignmentsAsync() {
4214
+ throw simulationUnavailableError();
4215
+ },
4216
+ async assignItemToSlotAsync() {
4217
+ throw simulationUnavailableError();
4218
+ },
4219
+ async removeItemFromSlotAsync() {
4220
+ throw simulationUnavailableError();
4221
+ },
4222
+ async getAvailableItemsAsync() {
4223
+ throw simulationUnavailableError();
4224
+ },
4225
+ async calculatePowerPreviewAsync() {
4226
+ throw simulationUnavailableError();
4227
+ },
4228
+ async validateSlotAssignmentAsync() {
4229
+ throw simulationUnavailableError();
4230
+ },
4231
+ async executeBatchOperationsAsync() {
4232
+ throw simulationUnavailableError();
4233
+ },
4234
+ async subscribeAsync() {
4235
+ throw simulationUnavailableError();
4236
+ }
4237
+ };
4238
+ }
4080
4239
  var MockHost = class {
4081
4240
  constructor(venusApi) {
4082
4241
  __publicField(this, "ads");
@@ -4089,9 +4248,9 @@ var MockHost = class {
4089
4248
  __publicField(this, "notifications");
4090
4249
  __publicField(this, "popups");
4091
4250
  __publicField(this, "profile");
4251
+ __publicField(this, "system");
4092
4252
  __publicField(this, "cdn");
4093
4253
  __publicField(this, "time");
4094
- __publicField(this, "post");
4095
4254
  __publicField(this, "ai");
4096
4255
  __publicField(this, "haptics");
4097
4256
  __publicField(this, "features");
@@ -4123,15 +4282,17 @@ var MockHost = class {
4123
4282
  this.navigation = new MockNavigationApi(venusApi);
4124
4283
  this.notifications = new MockNotificationsApi(venusApi);
4125
4284
  this.popups = new MockPopupsApi(this._overlay);
4126
- this.profile = new MockProfileApi();
4127
- this.cdn = new MockCdnApi();
4285
+ this.profile = new MockProfileApi(venusApi);
4286
+ const deviceApi = new MockDeviceApi(venusApi);
4287
+ const environmentApi = new MockEnvironmentApi(venusApi);
4288
+ this.system = new MockSystemApi(deviceApi, environmentApi, venusApi);
4289
+ this.cdn = new MockCdnApi(venusApi);
4128
4290
  this.time = new MockTimeApi(venusApi);
4129
- this.post = new MockPostApi(venusApi);
4130
4291
  this.ai = new MockAiApi();
4131
4292
  this.haptics = new MockHapticsApi(venusApi);
4132
4293
  this.features = new MockFeaturesApi();
4133
4294
  this.lifecycle = this._mockLifecyclesApi;
4134
- this.simulation = new MockSimulationApi();
4295
+ this.simulation = createUnavailableSimulationApi();
4135
4296
  this.rooms = createUnavailableRoomsApi();
4136
4297
  this.logging = new MockLoggingApi();
4137
4298
  this.iap = new MockIapApi();
@@ -4147,40 +4308,17 @@ var MockHost = class {
4147
4308
  }
4148
4309
  initialize(options) {
4149
4310
  this._isInitialized = true;
4150
- const controls = this.updateUiControls();
4311
+ this.venusApi._profileData = this.profile.getCurrentProfile();
4312
+ this.venusApi._deviceData = this.system.getDevice();
4313
+ this.venusApi._environmentData = this.system.getEnvironment();
4314
+ this.venusApi._localeData = this.venusApi._mock?.locale || "en-US";
4315
+ this.venusApi._languageCodeData = this.venusApi._mock?.languageCode || "en";
4151
4316
  return Promise.resolve({
4152
4317
  initializeAsleep: false,
4153
- hudInsets: {
4154
- top: controls.feedHeader.height,
4155
- bottom: 0,
4156
- left: 0,
4157
- right: 0
4158
- }
4318
+ safeArea: this.venusApi._safeAreaData
4159
4319
  });
4160
4320
  }
4161
- updateUiControls() {
4162
- const controls = {
4163
- closeButton: { x: 16, y: 16, width: 32, height: 32 },
4164
- menuButton: {
4165
- x: window.innerWidth - 48,
4166
- y: 16,
4167
- width: 32,
4168
- height: 32
4169
- },
4170
- feedHeader: { x: 0, y: 0, width: window.innerWidth, height: 56 },
4171
- playButton: {
4172
- x: 0,
4173
- y: window.innerHeight - 60,
4174
- width: window.innerWidth,
4175
- height: 60
4176
- }
4177
- };
4178
- return controls;
4179
- }
4180
4321
  createOverlay() {
4181
- const venusApi = this.venusApi;
4182
- venusApi.config.ui.controls = this.updateUiControls();
4183
- const uiControls = venusApi.config.ui.controls;
4184
4322
  const overlayContainer = document.createElement("div");
4185
4323
  overlayContainer.id = "venus-mock-overlay";
4186
4324
  overlayContainer.style.cssText = `
@@ -4196,7 +4334,7 @@ var MockHost = class {
4196
4334
  const menuButton = this.createOverlayButton(
4197
4335
  "close",
4198
4336
  "Menu",
4199
- uiControls.menuButton,
4337
+ { x: window.innerWidth - 48, y: 16, width: 32, height: 32 },
4200
4338
  () => {
4201
4339
  this.handleMenuButtonClicked();
4202
4340
  },
@@ -4425,17 +4563,13 @@ var MockHost = class {
4425
4563
  return button;
4426
4564
  }
4427
4565
  updateOverlayLayout() {
4428
- const venusApi = this.venusApi;
4429
4566
  const overlay = this._overlay;
4430
- venusApi.config.ui.controls = this.updateUiControls();
4431
- const uiControls = venusApi.config.ui.controls;
4432
4567
  const menuBtn = overlay.elements.menuButton;
4433
- const menuPos = uiControls.menuButton;
4434
- menuBtn.style.left = `${menuPos.x}px`;
4435
- menuBtn.style.top = `${menuPos.y}px`;
4436
- menuBtn.style.width = `${menuPos.width}px`;
4437
- menuBtn.style.minWidth = `${menuPos.width}px`;
4438
- menuBtn.style.height = `${menuPos.height}px`;
4568
+ menuBtn.style.left = `${window.innerWidth - 48}px`;
4569
+ menuBtn.style.top = "16px";
4570
+ menuBtn.style.width = "32px";
4571
+ menuBtn.style.minWidth = "32px";
4572
+ menuBtn.style.height = "32px";
4439
4573
  }
4440
4574
  triggerLifecycleEvent(name) {
4441
4575
  console.log("Trigger Lifecycle Event: ", name);
@@ -4664,6 +4798,16 @@ var VenusTransport = class {
4664
4798
  this.isProcessingMessage = false;
4665
4799
  return;
4666
4800
  }
4801
+ if (message.type === "H5_SIMULATION_UPDATE" /* H5_SIMULATION_UPDATE */) {
4802
+ const notification = {
4803
+ type: "rpc-notification",
4804
+ id: message.type,
4805
+ payload: message.data
4806
+ };
4807
+ this.handleNotification(notification);
4808
+ this.isProcessingMessage = false;
4809
+ return;
4810
+ }
4667
4811
  const requestId = messageData.requestId;
4668
4812
  if (!requestId) {
4669
4813
  this.logWarn("No requestId. Ignoring message...");
@@ -4830,294 +4974,6 @@ var VenusTransport = class {
4830
4974
  }
4831
4975
  };
4832
4976
 
4833
- // src/RemoteHost.ts
4834
- init_rooms();
4835
-
4836
- // src/rooms/RpcRoomsApi.ts
4837
- init_VenusRoom();
4838
- var RpcRoomsApi = class {
4839
- constructor(rpcClient) {
4840
- __publicField(this, "rpcClient");
4841
- __publicField(this, "subscriptions");
4842
- __publicField(this, "transportSubscription", null);
4843
- this.rpcClient = rpcClient;
4844
- this.subscriptions = {
4845
- data: {},
4846
- messages: {},
4847
- gameEvents: {},
4848
- allEvents: {}
4849
- };
4850
- }
4851
- /**
4852
- * Get the subscription state for external access (used by setupRoomNotifications)
4853
- */
4854
- getSubscriptions() {
4855
- return this.subscriptions;
4856
- }
4857
- /**
4858
- * Set up room notification routing from the transport
4859
- */
4860
- setupNotifications(transport) {
4861
- const { setupRoomNotifications: setupRoomNotifications2 } = (init_rooms(), __toCommonJS(rooms_exports));
4862
- this.transportSubscription = setupRoomNotifications2(
4863
- transport,
4864
- () => this.getSubscriptions()
4865
- );
4866
- }
4867
- /**
4868
- * Clean up subscriptions and resources
4869
- */
4870
- dispose() {
4871
- if (this.transportSubscription) {
4872
- this.transportSubscription.unsubscribe();
4873
- this.transportSubscription = null;
4874
- console.log("[Venus Rooms] Cleaned up room notification subscription");
4875
- }
4876
- }
4877
- async createRoom(options) {
4878
- const response = await this.rpcClient.call(
4879
- "H5_ROOM_CREATE" /* H5_ROOM_CREATE */,
4880
- {
4881
- options
4882
- }
4883
- );
4884
- if (response.success === false) {
4885
- throw new Error(response.error || "Failed to create room");
4886
- }
4887
- const roomData = response.roomData || response;
4888
- const room = new exports.VenusRoom(roomData);
4889
- return room;
4890
- }
4891
- async joinOrCreateRoom(options) {
4892
- const response = await this.rpcClient.call(
4893
- "H5_ROOM_JOIN_OR_CREATE" /* H5_ROOM_JOIN_OR_CREATE */,
4894
- {
4895
- options
4896
- }
4897
- );
4898
- if (response.success === false) {
4899
- throw new Error(response.error || "Failed to join or create room");
4900
- }
4901
- const data = response.value || response;
4902
- const room = new exports.VenusRoom(data.roomData);
4903
- return {
4904
- action: data.action,
4905
- room,
4906
- playersJoined: data.playersJoined
4907
- };
4908
- }
4909
- async joinRoomByCode(roomCode) {
4910
- const response = await this.rpcClient.call(
4911
- "H5_ROOM_JOIN_BY_CODE" /* H5_ROOM_JOIN_BY_CODE */,
4912
- {
4913
- roomCode
4914
- }
4915
- );
4916
- if (response?.success === false) {
4917
- throw new Error(response.error || "Failed to join room by code");
4918
- }
4919
- const roomData = response.roomData || response;
4920
- const room = new exports.VenusRoom(roomData);
4921
- return room;
4922
- }
4923
- // Get user's rooms with optional filtering
4924
- async getUserRooms(includeArchived = false) {
4925
- const response = await this.rpcClient.call(
4926
- "H5_ROOM_GET_USER_ROOMS" /* H5_ROOM_GET_USER_ROOMS */,
4927
- {
4928
- includeArchived
4929
- }
4930
- );
4931
- if (response?.success === false) {
4932
- throw new Error(response.error || "Failed to get user rooms");
4933
- }
4934
- const rawRooms = response.rooms || [];
4935
- const venusRooms = [];
4936
- for (const roomData of rawRooms) {
4937
- if (!roomData.id) {
4938
- console.warn("getUserRooms: Skipping room with missing ID:", roomData);
4939
- continue;
4940
- }
4941
- try {
4942
- const venusRoom = new exports.VenusRoom(roomData);
4943
- venusRooms.push(venusRoom);
4944
- } catch (error) {
4945
- console.warn(
4946
- "getUserRooms: Failed to create VenusRoom object:",
4947
- error,
4948
- roomData
4949
- );
4950
- }
4951
- }
4952
- return venusRooms;
4953
- }
4954
- async updateData(room, updates, merge = true) {
4955
- const response = await this.rpcClient.call(
4956
- "H5_ROOM_UPDATE_DATA" /* H5_ROOM_UPDATE_DATA */,
4957
- {
4958
- roomId: room.id,
4959
- updates,
4960
- merge
4961
- }
4962
- );
4963
- if (response?.success === false) {
4964
- throw new Error(response.error || "Failed to update room data");
4965
- }
4966
- return response.data;
4967
- }
4968
- async getData(room) {
4969
- const response = await this.rpcClient.call(
4970
- "H5_ROOM_GET_DATA" /* H5_ROOM_GET_DATA */,
4971
- {
4972
- roomId: room.id
4973
- }
4974
- );
4975
- if (response?.success === false) {
4976
- throw new Error(response.error || "Failed to get room data");
4977
- }
4978
- return response.data;
4979
- }
4980
- async sendMessage(venusRoom, messageData) {
4981
- const response = await this.rpcClient.call(
4982
- "H5_ROOM_SEND_MESSAGE" /* H5_ROOM_SEND_MESSAGE */,
4983
- {
4984
- roomId: venusRoom.id,
4985
- message: messageData
4986
- }
4987
- );
4988
- if (response?.success === false) {
4989
- throw new Error(response.error || "Failed to send message");
4990
- }
4991
- return response.messageId;
4992
- }
4993
- async leave(room) {
4994
- const response = await this.rpcClient.call(
4995
- "H5_ROOM_LEAVE" /* H5_ROOM_LEAVE */,
4996
- {
4997
- roomId: room.id
4998
- }
4999
- );
5000
- if (response?.success === false) {
5001
- throw new Error(response.error || "Failed to leave room");
5002
- }
5003
- return response;
5004
- }
5005
- async startGame(room, gameConfig = {}, turnOrder = null) {
5006
- const response = await this.rpcClient.call(
5007
- "H5_ROOM_START_GAME" /* H5_ROOM_START_GAME */,
5008
- {
5009
- roomId: room.id,
5010
- gameConfig,
5011
- turnOrder
5012
- }
5013
- );
5014
- if (response?.success === false) {
5015
- throw new Error(response.error || "Failed to start game");
5016
- }
5017
- return response.data;
5018
- }
5019
- async proposeMove(room, proposalPayload) {
5020
- const response = await this.rpcClient.call(
5021
- "h5:room:proposeMove" /* H5_ROOM_PROPOSE_MOVE */,
5022
- {
5023
- roomId: room.id,
5024
- gameSpecificState: proposalPayload.gameSpecificState,
5025
- moveType: proposalPayload.moveType,
5026
- clientContext: proposalPayload.clientContext,
5027
- clientProposalId: proposalPayload.clientProposalId
5028
- }
5029
- );
5030
- if (response?.success === false) {
5031
- throw new Error(response.error || "Failed to propose move");
5032
- }
5033
- return response.data;
5034
- }
5035
- async validateMove(room, moveId, isValid, reason = null, validatorId = null) {
5036
- console.log(`[Venus Rooms] Validating move ${moveId}: ${isValid}`);
5037
- return { success: true, moveId, isValid, reason };
5038
- }
5039
- async roomSubscribeToGameEvents(room, callback) {
5040
- "game_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
5041
- if (!this.subscriptions.gameEvents[room.id]) {
5042
- this.subscriptions.gameEvents[room.id] = [];
5043
- }
5044
- this.subscriptions.gameEvents[room.id].push(callback);
5045
- }
5046
- subscribe(room, options = {}) {
5047
- const subscriptionIds = [];
5048
- const roomId = room.id;
5049
- if (options.onData) {
5050
- const dataSubId = "data_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
5051
- if (!this.subscriptions.data[roomId]) {
5052
- this.subscriptions.data[roomId] = [];
5053
- }
5054
- this.subscriptions.data[roomId].push(options.onData);
5055
- subscriptionIds.push({
5056
- type: "data",
5057
- id: dataSubId,
5058
- callback: options.onData
5059
- });
5060
- }
5061
- if (options.onMessages) {
5062
- const msgSubId = "messages_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
5063
- if (!this.subscriptions.messages[roomId]) {
5064
- this.subscriptions.messages[roomId] = [];
5065
- }
5066
- this.subscriptions.messages[roomId].push(options.onMessages);
5067
- subscriptionIds.push({
5068
- type: "messages",
5069
- id: msgSubId,
5070
- callback: options.onMessages
5071
- });
5072
- }
5073
- if (options.onMoves || options.onGameEvents) {
5074
- const handler = options.onMoves || options.onGameEvents;
5075
- if (handler) {
5076
- const gameSubId = "game_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
5077
- if (!this.subscriptions.gameEvents[roomId]) {
5078
- this.subscriptions.gameEvents[roomId] = [];
5079
- }
5080
- this.subscriptions.gameEvents[roomId].push(handler);
5081
- subscriptionIds.push({
5082
- type: "gameEvents",
5083
- id: gameSubId,
5084
- callback: handler
5085
- });
5086
- }
5087
- }
5088
- 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;
5089
- if (needsSubscription) {
5090
- this.rpcClient.call("H5_ROOM_SUBSCRIBE" /* H5_ROOM_SUBSCRIBE */, {
5091
- roomId,
5092
- subscribeToData: !!options.onData,
5093
- subscribeToMessages: !!options.onMessages,
5094
- subscribeToProposedMoves: !!(options.onMoves || options.onGameEvents)
5095
- }).catch((error) => {
5096
- console.error("Failed to set up room subscription:", error);
5097
- });
5098
- }
5099
- let called = false;
5100
- return () => {
5101
- if (called) return;
5102
- called = true;
5103
- subscriptionIds.forEach((sub) => {
5104
- const bucket = this.subscriptions[sub.type];
5105
- const callbacks = bucket && bucket[roomId] || [];
5106
- const index = callbacks.indexOf(sub.callback);
5107
- if (index > -1) callbacks.splice(index, 1);
5108
- });
5109
- const hasNoCallbacks = (this.subscriptions.data[roomId]?.length ?? 0) === 0 && (this.subscriptions.messages[roomId]?.length ?? 0) === 0 && (this.subscriptions.gameEvents[roomId]?.length ?? 0) === 0;
5110
- if (hasNoCallbacks) {
5111
- this.rpcClient.call("H5_ROOM_UNSUBSCRIBE" /* H5_ROOM_UNSUBSCRIBE */, {
5112
- roomId
5113
- }).catch((error) => {
5114
- console.error("Failed to clean up room subscription:", error);
5115
- });
5116
- }
5117
- };
5118
- }
5119
- };
5120
-
5121
4977
  // src/social/RpcSocialApi.ts
5122
4978
  var RpcSocialApi = class {
5123
4979
  constructor(rpcClient) {
@@ -5164,9 +5020,9 @@ var RemoteHost = class {
5164
5020
  __publicField(this, "notifications");
5165
5021
  __publicField(this, "popups");
5166
5022
  __publicField(this, "profile");
5023
+ __publicField(this, "system");
5167
5024
  __publicField(this, "cdn");
5168
5025
  __publicField(this, "time");
5169
- __publicField(this, "post");
5170
5026
  __publicField(this, "ai");
5171
5027
  __publicField(this, "haptics");
5172
5028
  __publicField(this, "features");
@@ -5220,10 +5076,12 @@ var RemoteHost = class {
5220
5076
  this.navigation = new RpcNavigationApi(rpcClient, venusApi);
5221
5077
  this.notifications = new RpcNotificationsApi(rpcClient);
5222
5078
  this.popups = new RpcPopupsApi(rpcClient);
5223
- this.profile = new HostProfileApi();
5079
+ this.profile = new HostProfileApi(venusApi);
5080
+ const deviceApi = new HostDeviceApi(venusApi);
5081
+ const environmentApi = new HostEnvironmentApi(venusApi);
5082
+ this.system = new HostSystemApi(deviceApi, environmentApi, venusApi);
5224
5083
  this.cdn = new HostCdnApi(getCdnBaseUrl());
5225
- this.time = new HostTimeApi(rpcClient);
5226
- this.post = new RpcPostApi(rpcClient);
5084
+ this.time = new HostTimeApi(rpcClient, venusApi);
5227
5085
  this.ai = new RpcAiApi(rpcClient);
5228
5086
  this.haptics = new RpcHapticsApi(rpcClient);
5229
5087
  this.features = new RpcFeaturesApi(rpcClient);
@@ -5238,7 +5096,6 @@ var RemoteHost = class {
5238
5096
  venusApi.isMock = () => false;
5239
5097
  this.venusApi.sharedAssets = new RpcSharedAssetsApi(rpcClient, venusApi);
5240
5098
  initializeRoomsApi(this.venusApi, this);
5241
- console.log("[Venus SDK] Remote host created");
5242
5099
  }
5243
5100
  get isInitialized() {
5244
5101
  return this._isInitialized;
@@ -5257,35 +5114,27 @@ var RemoteHost = class {
5257
5114
  );
5258
5115
  transport.instanceId = response.instanceId;
5259
5116
  this.log(`Remote Host Initialized with id: ${transport.instanceId}`);
5260
- if (response.profile) {
5261
- const profile = response.profile;
5262
- const sanitizedProfile = {
5263
- id: profile.id,
5264
- username: profile.username,
5265
- avatarUrl: profile.avatarUrl ?? null,
5266
- isAnonymous: Boolean(profile.isAnonymous)
5267
- };
5268
- if (typeof window !== "undefined") {
5269
- const globalWindow = window;
5270
- const venus = globalWindow.venus || (globalWindow.venus = {});
5271
- venus.profile = sanitizedProfile;
5272
- if (venus._config) {
5273
- venus._config.profile = sanitizedProfile;
5274
- }
5275
- if (venus.config) {
5276
- venus.config.profile = sanitizedProfile;
5277
- }
5278
- }
5279
- }
5117
+ const profile = response.profile;
5118
+ const sanitizedProfile = {
5119
+ id: profile.id,
5120
+ username: profile.username,
5121
+ avatarUrl: profile.avatarUrl ?? null,
5122
+ isAnonymous: Boolean(profile.isAnonymous)
5123
+ };
5124
+ this.venusApi._profileData = sanitizedProfile;
5125
+ this.venusApi._deviceData = response.device;
5126
+ this.venusApi._environmentData = response.environment;
5127
+ this.venusApi._localeData = response.locale;
5128
+ this.venusApi._languageCodeData = response.languageCode;
5280
5129
  this._isInitialized = true;
5281
- this.venusApi.launchParams = response.launchParams || {};
5130
+ this.venusApi.launchParams = response.launchParams;
5282
5131
  await this.rpcClient.call("READY" /* READY */, {});
5283
- const hudInsets = response.hudInsets;
5284
- if (hudInsets) {
5285
- this.venusApi.config.ui.safeArea = hudInsets;
5132
+ const safeArea = response.safeArea;
5133
+ if (safeArea) {
5134
+ this.venusApi._safeAreaData = safeArea;
5286
5135
  }
5287
5136
  return {
5288
- hudInsets,
5137
+ safeArea,
5289
5138
  initializeAsleep: response.initializeAsleep
5290
5139
  };
5291
5140
  }
@@ -5297,10 +5146,8 @@ var RemoteHost = class {
5297
5146
  // src/Host.ts
5298
5147
  function createHost(venusApi, isMock) {
5299
5148
  if (isMock) {
5300
- console.log("[Venus SDK] Creating Local Host");
5301
5149
  return new MockHost(venusApi);
5302
5150
  } else {
5303
- console.log("[Venus SDK] Creating Remote Host");
5304
5151
  return new RemoteHost(venusApi);
5305
5152
  }
5306
5153
  }
@@ -5313,15 +5160,35 @@ function initializeSocial(venusApi, host) {
5313
5160
  };
5314
5161
  }
5315
5162
 
5163
+ // raw-loader:/Users/pchan/Development/series/venus/venus-sdk/packages/api/src/webview/webviewLibraryShim.js
5164
+ var webviewLibraryShim_default = "/**\r\n * Venus Embedded Libraries WebView Shim\r\n *\r\n * This code is injected into H5 game WebViews BEFORE the game's main script runs.\r\n * It bootstraps the embedded libraries system by:\r\n * 1. Reading window.__venusLibrariesConfig (set by the Vite plugin)\r\n * 2. Loading libraries via RPC (mobile) or CDN (web)\r\n * 3. Registering libraries in window.__venusLibraryExports\r\n * 4. Allowing the game's virtual modules to access them\r\n *\r\n * This shim is NOT imported by H5 games - it's injected by the Venus host via\r\n * injectedJavaScriptBeforeContentLoaded in H5AppPoolRenderer.\r\n */\r\n\r\n;(function () {\r\n if (typeof window === 'undefined') {\r\n return\r\n }\r\n\r\n if (window.__venusLibraryShim && window.__venusLibraryShim.__initialized) {\r\n return\r\n }\r\n\r\n var RESPONSE_TYPE = 'H5_RESPONSE'\r\n var REQUEST_TYPE = 'H5_LOAD_EMBEDDED_ASSET'\r\n var REQUEST_TIMEOUT_MS = 12000\r\n var pendingRequests = new Map()\r\n\r\n function ensureConfig() {\r\n if (!window.__venusLibrariesConfig) {\r\n window.__venusLibrariesConfig = {\r\n enabled: false,\r\n required: [],\r\n manifest: {},\r\n cdnBase: '',\r\n }\r\n }\r\n if (!window.__venusLibrariesConfig.manifest) {\r\n window.__venusLibrariesConfig.manifest = {}\r\n }\r\n if (!Array.isArray(window.__venusLibrariesConfig.required)) {\r\n window.__venusLibrariesConfig.required = []\r\n }\r\n return window.__venusLibrariesConfig\r\n }\r\n\r\n function ensureExportsRegistry() {\r\n if (!window.__venusLibraryExports) {\r\n window.__venusLibraryExports = {}\r\n }\r\n return window.__venusLibraryExports\r\n }\r\n\r\n function hasHostBridge() {\r\n return !!(\r\n window.ReactNativeWebView &&\r\n typeof window.ReactNativeWebView.postMessage === 'function'\r\n )\r\n }\r\n\r\n function registerResponseListeners() {\r\n if (\r\n window.__venusLibraryShim &&\r\n window.__venusLibraryShim.__listenerRegistered\r\n ) {\r\n return\r\n }\r\n\r\n function handleMessage(event) {\r\n var payload = parsePayload(event && event.data)\r\n if (!payload || payload.type !== RESPONSE_TYPE || !payload.data) {\r\n return\r\n }\r\n var requestId = payload.data.requestId\r\n if (!requestId || !pendingRequests.has(requestId)) {\r\n return\r\n }\r\n var pending = pendingRequests.get(requestId)\r\n pendingRequests.delete(requestId)\r\n clearTimeout(pending.timeout)\r\n\r\n if (payload.data.success === false) {\r\n pending.reject(\r\n new Error(payload.data.error || 'Embedded library load failed'),\r\n )\r\n return\r\n }\r\n\r\n var value = payload.data.value || payload.data\r\n if (!value || !value.base64Data) {\r\n pending.reject(\r\n new Error('Embedded library response was missing base64Data'),\r\n )\r\n return\r\n }\r\n\r\n pending.resolve(value.base64Data)\r\n }\r\n\r\n if (\r\n typeof document !== 'undefined' &&\r\n typeof document.addEventListener === 'function'\r\n ) {\r\n document.addEventListener('message', handleMessage, false)\r\n }\r\n if (\r\n typeof window !== 'undefined' &&\r\n typeof window.addEventListener === 'function'\r\n ) {\r\n window.addEventListener('message', handleMessage, false)\r\n }\r\n\r\n if (!window.__venusLibraryShim) {\r\n window.__venusLibraryShim = {}\r\n }\r\n window.__venusLibraryShim.__listenerRegistered = true\r\n }\r\n\r\n function parsePayload(raw) {\r\n if (!raw || typeof raw !== 'string') {\r\n return null\r\n }\r\n try {\r\n return JSON.parse(raw)\r\n } catch (error) {\r\n return null\r\n }\r\n }\r\n\r\n function createRequestId(libraryKey) {\r\n var sanitized = ''\r\n for (var i = 0; i < libraryKey.length; i++) {\r\n var c = libraryKey.charAt(i)\r\n if (\r\n (c >= 'a' && c <= 'z') ||\r\n (c >= 'A' && c <= 'Z') ||\r\n (c >= '0' && c <= '9') ||\r\n c === '-' ||\r\n c === '_'\r\n ) {\r\n sanitized += c\r\n } else {\r\n sanitized += '_'\r\n }\r\n }\r\n return (\r\n 'embedded-lib-' +\r\n sanitized +\r\n '-' +\r\n Date.now() +\r\n '-' +\r\n Math.random().toString(36).slice(2)\r\n )\r\n }\r\n\r\n function postHostRequest(assetKey, requestId) {\r\n if (!hasHostBridge()) {\r\n throw new Error('Host bridge is unavailable')\r\n }\r\n var bridge = window.ReactNativeWebView\r\n var message = {\r\n type: REQUEST_TYPE,\r\n direction: 'H5_TO_APP',\r\n data: {\r\n requestId: requestId,\r\n assetKey: assetKey,\r\n },\r\n instanceId:\r\n (window._venusInitState && window._venusInitState.poolId) || 'unknown',\r\n timestamp: Date.now(),\r\n }\r\n bridge.postMessage(JSON.stringify(message))\r\n }\r\n\r\n function loadLibraryViaHost(assetKey, libraryKey) {\r\n return new Promise(function (resolve, reject) {\r\n var requestId = createRequestId(libraryKey)\r\n var timeout = setTimeout(function () {\r\n pendingRequests.delete(requestId)\r\n reject(new Error('Timed out loading embedded library: ' + libraryKey))\r\n }, REQUEST_TIMEOUT_MS)\r\n\r\n pendingRequests.set(requestId, {\r\n resolve: resolve,\r\n reject: reject,\r\n timeout: timeout,\r\n })\r\n\r\n try {\r\n postHostRequest(assetKey, requestId)\r\n } catch (error) {\r\n pendingRequests.delete(requestId)\r\n clearTimeout(timeout)\r\n reject(error)\r\n }\r\n })\r\n }\r\n\r\n function buildCdnUrl(config, entry) {\r\n var base = config.cdnBase || ''\r\n if (!base.endsWith('/')) {\r\n base += '/'\r\n }\r\n var path = entry.cdnPath\r\n if (path.charAt(0) === '/') {\r\n path = path.substring(1)\r\n }\r\n return base + path\r\n }\r\n\r\n async function loadLibraryViaCdn(config, entry, libraryKey) {\r\n if (!config.cdnBase) {\r\n throw new Error('CDN base URL is not configured')\r\n }\r\n var url = buildCdnUrl(config, entry)\r\n var response = await fetch(url, { credentials: 'omit' })\r\n if (!response.ok) {\r\n throw new Error(\r\n 'Failed to fetch embedded library from CDN: ' + libraryKey,\r\n )\r\n }\r\n return await response.text()\r\n }\r\n\r\n function decodeBase64ToUtf8(base64) {\r\n if (typeof base64 !== 'string') {\r\n throw new Error('Invalid base64 payload')\r\n }\r\n\r\n if (typeof atob === 'function') {\r\n var binary = atob(base64)\r\n if (typeof TextDecoder !== 'undefined') {\r\n var len = binary.length\r\n var bytes = new Uint8Array(len)\r\n for (var i = 0; i < len; i++) {\r\n bytes[i] = binary.charCodeAt(i)\r\n }\r\n return new TextDecoder('utf-8').decode(bytes)\r\n }\r\n return decodeURIComponent(escape(binary))\r\n }\r\n\r\n var bufferCtor =\r\n (typeof globalThis !== 'undefined' && globalThis.Buffer) ||\r\n (typeof window !== 'undefined' && window.Buffer)\r\n if (bufferCtor) {\r\n return bufferCtor.from(base64, 'base64').toString('utf-8')\r\n }\r\n\r\n throw new Error('No base64 decoder available')\r\n }\r\n\r\n function evaluateLibrarySource(libraryKey, globalVar, source) {\r\n var registry = ensureExportsRegistry()\r\n if (!source) {\r\n throw new Error('Embedded library source was empty for ' + libraryKey)\r\n }\r\n\r\n var previousValue = window[globalVar]\r\n try {\r\n var executor = new Function(\r\n source + '\\n//# sourceURL=venus-library-' + libraryKey + '.js',\r\n )\r\n executor.call(window)\r\n } catch (error) {\r\n throw new Error(\r\n 'Failed to evaluate embedded library ' +\r\n libraryKey +\r\n ': ' +\r\n (error && error.message ? error.message : error),\r\n )\r\n }\r\n\r\n var exported = window[globalVar] || previousValue\r\n if (!exported) {\r\n throw new Error(\r\n 'Embedded library ' + libraryKey + ' did not register ' + globalVar,\r\n )\r\n }\r\n\r\n registry[libraryKey] = exported\r\n return exported\r\n }\r\n\r\n async function ensureLibraryLoaded(config, libraryKey) {\r\n var registry = ensureExportsRegistry()\r\n if (registry[libraryKey]) {\r\n return registry[libraryKey]\r\n }\r\n\r\n var entry = config.manifest && config.manifest[libraryKey]\r\n if (!entry) {\r\n throw new Error('No manifest entry for embedded library ' + libraryKey)\r\n }\r\n\r\n var source = null\r\n if (config.useHost !== false && hasHostBridge()) {\r\n try {\r\n var base64 = await loadLibraryViaHost(entry.assetKey, libraryKey)\r\n source = decodeBase64ToUtf8(base64)\r\n } catch (error) {\r\n // Log the RPC error loudly before fallback\r\n console.error(\r\n '[Venus Libraries] Failed to load ' +\r\n libraryKey +\r\n ' from host via RPC:',\r\n error,\r\n )\r\n console.warn(\r\n '[Venus Libraries] Falling back to CDN for ' +\r\n libraryKey +\r\n '. This may indicate an asset packaging issue.',\r\n )\r\n }\r\n }\r\n\r\n if (!source) {\r\n source = await loadLibraryViaCdn(config, entry, libraryKey)\r\n }\r\n\r\n return evaluateLibrarySource(libraryKey, entry.globalVar, source)\r\n }\r\n\r\n async function bootstrap() {\r\n try {\r\n registerResponseListeners()\r\n getBootstrapPromise()\r\n\r\n var config = ensureConfig()\r\n\r\n if (!config.enabled) {\r\n if (bootstrapResolve) bootstrapResolve()\r\n return\r\n }\r\n\r\n if (!Array.isArray(config.required) || config.required.length === 0) {\r\n if (bootstrapResolve) bootstrapResolve()\r\n return\r\n }\r\n\r\n // Group libraries by load stage for parallel loading within stages\r\n var librariesByStage = {}\r\n for (var i = 0; i < config.required.length; i++) {\r\n var libraryKey = config.required[i]\r\n var entry = config.manifest[libraryKey]\r\n var stage = entry.loadStage || 0\r\n if (!librariesByStage[stage]) librariesByStage[stage] = []\r\n librariesByStage[stage].push(libraryKey)\r\n }\r\n\r\n // Load stages sequentially, libraries within each stage in parallel\r\n var stages = Object.keys(librariesByStage).sort(function (a, b) {\r\n return parseInt(a, 10) - parseInt(b, 10)\r\n })\r\n\r\n for (var s = 0; s < stages.length; s++) {\r\n var stage = stages[s]\r\n var libs = librariesByStage[stage]\r\n\r\n // Load all libraries in this stage in parallel\r\n var stagePromises = libs.map(function (libraryKey) {\r\n return ensureLibraryLoaded(config, libraryKey).catch(\r\n function (error) {\r\n console.error(\r\n '[Venus Libraries] Failed to load library ' + libraryKey,\r\n error,\r\n )\r\n throw error\r\n },\r\n )\r\n })\r\n\r\n await Promise.all(stagePromises)\r\n }\r\n\r\n if (bootstrapResolve) bootstrapResolve()\r\n } catch (error) {\r\n console.error('[Venus Libraries] Bootstrap error', error)\r\n if (bootstrapReject) bootstrapReject(error)\r\n throw error\r\n }\r\n }\r\n\r\n // Create a promise that resolves when bootstrap completes\r\n var bootstrapPromise = null\r\n var bootstrapResolve = null\r\n var bootstrapReject = null\r\n\r\n function getBootstrapPromise() {\r\n if (!bootstrapPromise) {\r\n bootstrapPromise = new Promise(function (resolve, reject) {\r\n bootstrapResolve = resolve\r\n bootstrapReject = reject\r\n })\r\n }\r\n return bootstrapPromise\r\n }\r\n\r\n window.__venusLibraryShim = {\r\n bootstrap: bootstrap,\r\n ready: getBootstrapPromise,\r\n getExports: function (libraryKey) {\r\n var registry = ensureExportsRegistry()\r\n return registry[libraryKey]\r\n },\r\n __initialized: true,\r\n }\r\n})()\r\n";
5165
+
5166
+ // src/webview/webviewLibraryShimSource.ts
5167
+ var WEBVIEW_LIBRARY_SHIM_SOURCE = webviewLibraryShim_default;
5168
+ function getWebviewLibraryShimSource() {
5169
+ return WEBVIEW_LIBRARY_SHIM_SOURCE;
5170
+ }
5171
+
5172
+ exports.DEFAULT_SHARED_LIB_CDN_BASE = DEFAULT_SHARED_LIB_CDN_BASE;
5173
+ exports.EMBEDDED_LIBRARIES = EMBEDDED_LIBRARIES;
5174
+ exports.EMBEDDED_LIBRARY_BY_KEY = EMBEDDED_LIBRARY_BY_KEY;
5175
+ exports.HASH_ALGORITHM_NODE = HASH_ALGORITHM_NODE;
5176
+ exports.HASH_ALGORITHM_WEB_CRYPTO = HASH_ALGORITHM_WEB_CRYPTO;
5316
5177
  exports.HapticFeedbackStyle = HapticFeedbackStyle;
5317
5178
  exports.HostCdnApi = HostCdnApi;
5179
+ exports.HostDeviceApi = HostDeviceApi;
5180
+ exports.HostEnvironmentApi = HostEnvironmentApi;
5318
5181
  exports.HostProfileApi = HostProfileApi;
5182
+ exports.HostSystemApi = HostSystemApi;
5319
5183
  exports.HostTimeApi = HostTimeApi;
5184
+ exports.MODULE_TO_LIBRARY_SPECIFIERS = MODULE_TO_LIBRARY_SPECIFIERS;
5320
5185
  exports.MockAdsApi = MockAdsApi;
5321
5186
  exports.MockAiApi = MockAiApi;
5322
5187
  exports.MockAnalyticsApi = MockAnalyticsApi;
5323
5188
  exports.MockAvatarApi = MockAvatarApi;
5324
5189
  exports.MockCdnApi = MockCdnApi;
5190
+ exports.MockDeviceApi = MockDeviceApi;
5191
+ exports.MockEnvironmentApi = MockEnvironmentApi;
5325
5192
  exports.MockFeaturesApi = MockFeaturesApi;
5326
5193
  exports.MockHapticsApi = MockHapticsApi;
5327
5194
  exports.MockIapApi = MockIapApi;
@@ -5334,9 +5201,9 @@ exports.MockPopupsApi = MockPopupsApi;
5334
5201
  exports.MockPreloaderApi = MockPreloaderApi;
5335
5202
  exports.MockProfileApi = MockProfileApi;
5336
5203
  exports.MockSharedAssetsApi = MockSharedAssetsApi;
5337
- exports.MockSimulationApi = MockSimulationApi;
5338
5204
  exports.MockSocialApi = MockSocialApi;
5339
5205
  exports.MockStorageApi = MockStorageApi;
5206
+ exports.MockSystemApi = MockSystemApi;
5340
5207
  exports.MockTimeApi = MockTimeApi;
5341
5208
  exports.RemoteHost = RemoteHost;
5342
5209
  exports.RpcAdsApi = RpcAdsApi;
@@ -5354,14 +5221,22 @@ exports.RpcNavigationApi = RpcNavigationApi;
5354
5221
  exports.RpcNotificationsApi = RpcNotificationsApi;
5355
5222
  exports.RpcPopupsApi = RpcPopupsApi;
5356
5223
  exports.RpcPreloaderApi = RpcPreloaderApi;
5224
+ exports.RpcRoomsApi = RpcRoomsApi;
5357
5225
  exports.RpcSharedAssetsApi = RpcSharedAssetsApi;
5358
5226
  exports.RpcSimulationApi = RpcSimulationApi;
5359
5227
  exports.RpcSocialApi = RpcSocialApi;
5360
5228
  exports.RpcStorageApi = RpcStorageApi;
5361
5229
  exports.SDK_VERSION = SDK_VERSION;
5362
5230
  exports.VenusMessageId = VenusMessageId;
5231
+ exports.VenusRoom = VenusRoom;
5232
+ exports.WEBVIEW_LIBRARY_SHIM_SOURCE = WEBVIEW_LIBRARY_SHIM_SOURCE;
5233
+ exports.base64ToArrayBuffer = base64ToArrayBuffer;
5234
+ exports.base64ToUtf8 = base64ToUtf8;
5235
+ exports.computeScoreHash = computeScoreHash;
5363
5236
  exports.createHost = createHost;
5364
5237
  exports.createMockStorageApi = createMockStorageApi;
5238
+ exports.getLibraryDefinition = getLibraryDefinition;
5239
+ exports.getWebviewLibraryShimSource = getWebviewLibraryShimSource;
5365
5240
  exports.initializeAds = initializeAds;
5366
5241
  exports.initializeAi = initializeAi;
5367
5242
  exports.initializeAnalytics = initializeAnalytics;
@@ -5382,6 +5257,7 @@ exports.initializeSimulation = initializeSimulation;
5382
5257
  exports.initializeSocial = initializeSocial;
5383
5258
  exports.initializeStackNavigation = initializeStackNavigation;
5384
5259
  exports.initializeStorage = initializeStorage;
5260
+ exports.initializeSystem = initializeSystem;
5385
5261
  exports.initializeTime = initializeTime;
5386
5262
  exports.isPacificDaylightTime = isPacificDaylightTime;
5387
5263
  exports.setupRoomNotifications = setupRoomNotifications;