@series-inc/venus-sdk 3.0.4 → 3.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +324 -123
  2. package/dist/{AdsApi-CNGRf6j0.d.mts → AdsApi-meVfUcZy.d.mts} +37 -25
  3. package/dist/{AdsApi-CNGRf6j0.d.ts → AdsApi-meVfUcZy.d.ts} +37 -25
  4. package/dist/chunk-2PDL7CQK.mjs +26 -0
  5. package/dist/chunk-2PDL7CQK.mjs.map +1 -0
  6. package/dist/{chunk-PXWCNWJ6.mjs → chunk-EMVTVSGL.mjs} +421 -109
  7. package/dist/chunk-EMVTVSGL.mjs.map +1 -0
  8. package/dist/chunk-IZLOB7DV.mjs +343 -0
  9. package/dist/chunk-IZLOB7DV.mjs.map +1 -0
  10. package/dist/{chunk-W7IPHM67.mjs → chunk-QABXMFND.mjs} +3 -26
  11. package/dist/chunk-QABXMFND.mjs.map +1 -0
  12. package/dist/core-5JLON75E.mjs +4 -0
  13. package/dist/{core-R3FHW62G.mjs.map → core-5JLON75E.mjs.map} +1 -1
  14. package/dist/index.cjs +768 -105
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.mts +140 -25
  17. package/dist/index.d.ts +140 -25
  18. package/dist/index.mjs +5 -3
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/venus-api/index.cjs +452 -101
  21. package/dist/venus-api/index.cjs.map +1 -1
  22. package/dist/venus-api/index.d.mts +2 -2
  23. package/dist/venus-api/index.d.ts +2 -2
  24. package/dist/venus-api/index.mjs +46 -3
  25. package/dist/venus-api/index.mjs.map +1 -1
  26. package/dist/vite/index.cjs +534 -0
  27. package/dist/vite/index.cjs.map +1 -0
  28. package/dist/vite/index.mjs +527 -0
  29. package/dist/vite/index.mjs.map +1 -0
  30. package/dist/webview/index.cjs +346 -0
  31. package/dist/webview/index.cjs.map +1 -0
  32. package/dist/webview/index.d.mts +17 -0
  33. package/dist/webview/index.d.ts +17 -0
  34. package/dist/webview/index.mjs +4 -0
  35. package/dist/webview/index.mjs.map +1 -0
  36. package/package.json +19 -1
  37. package/dist/chunk-PXWCNWJ6.mjs.map +0 -1
  38. package/dist/chunk-W7IPHM67.mjs.map +0 -1
  39. package/dist/core-R3FHW62G.mjs +0 -3
@@ -1157,9 +1157,11 @@ function isPacificDaylightTime(date) {
1157
1157
 
1158
1158
  // src/time/HostTimeApi.ts
1159
1159
  var HostTimeApi = class {
1160
- constructor(rpcClient) {
1160
+ constructor(rpcClient, venusApi) {
1161
1161
  __publicField(this, "rpcClient");
1162
+ __publicField(this, "venusApi");
1162
1163
  this.rpcClient = rpcClient;
1164
+ this.venusApi = venusApi;
1163
1165
  }
1164
1166
  async requestTimeAsync() {
1165
1167
  const response = await this.rpcClient.call(
@@ -1169,13 +1171,7 @@ var HostTimeApi = class {
1169
1171
  return response;
1170
1172
  }
1171
1173
  formatTime(timestamp, options) {
1172
- let locale = "en-US";
1173
- const windowVenus = window.venus;
1174
- if (windowVenus._config.locale) {
1175
- locale = windowVenus._config.locale;
1176
- } else if (windowVenus._config.environment && windowVenus._config.environment.browserInfo && windowVenus._config.environment.browserInfo.language) {
1177
- locale = windowVenus._config.environment.browserInfo.language;
1178
- }
1174
+ const locale = this.venusApi.getLocale();
1179
1175
  const date = new Date(timestamp);
1180
1176
  const dateTimeOptions = {
1181
1177
  dateStyle: options.dateStyle || "medium",
@@ -1187,13 +1183,7 @@ var HostTimeApi = class {
1187
1183
  }
1188
1184
  formatNumber(value, options) {
1189
1185
  try {
1190
- let locale = "en-US";
1191
- const windowVenus = window.venus;
1192
- if (windowVenus._config.locale) {
1193
- locale = windowVenus._config.locale;
1194
- } else if (windowVenus._config.environment && windowVenus._config.environment.browserInfo && windowVenus._config.environment.browserInfo.language) {
1195
- locale = windowVenus._config.environment.browserInfo.language;
1196
- }
1186
+ const locale = this.venusApi.getLocale();
1197
1187
  const numberOptions = {
1198
1188
  style: options?.style || "decimal",
1199
1189
  minimumFractionDigits: options?.minimumFractionDigits || 0,
@@ -1257,7 +1247,7 @@ var MockTimeApi = class {
1257
1247
  this.venusApi = venusApi;
1258
1248
  }
1259
1249
  formatNumber(value, options) {
1260
- const locale = this.getLocale();
1250
+ const locale = this.venusApi.getLocale();
1261
1251
  const numberOptions = {
1262
1252
  style: options?.style || "decimal",
1263
1253
  minimumFractionDigits: options?.minimumFractionDigits || 0,
@@ -1268,7 +1258,7 @@ var MockTimeApi = class {
1268
1258
  return value.toLocaleString(locale, numberOptions);
1269
1259
  }
1270
1260
  formatTime(timestamp, options) {
1271
- const locale = this.getLocale();
1261
+ const locale = this.venusApi.getLocale();
1272
1262
  const date = new Date(timestamp);
1273
1263
  const dateTimeOptions = {
1274
1264
  dateStyle: options.dateStyle || "medium",
@@ -1348,16 +1338,6 @@ var MockTimeApi = class {
1348
1338
  });
1349
1339
  return timeInfo;
1350
1340
  }
1351
- getLocale() {
1352
- const venusApi = this.venusApi;
1353
- let locale = "en-US";
1354
- if (venusApi._mock.user && venusApi._mock.user.locale) {
1355
- locale = venusApi._mock.user.locale;
1356
- } else if (venusApi._mock.environment && venusApi._mock.environment.browserInfo.language) {
1357
- locale = venusApi._mock.environment.browserInfo.language;
1358
- }
1359
- return locale;
1360
- }
1361
1341
  };
1362
1342
 
1363
1343
  // src/time/index.ts
@@ -3976,47 +3956,105 @@ function initializeIap(venusApiInstance, host) {
3976
3956
  venusApiInstance.iap = host.iap;
3977
3957
  }
3978
3958
 
3959
+ // src/leaderboard/utils.ts
3960
+ var HASH_ALGORITHM_WEB_CRYPTO = "SHA-256";
3961
+ async function computeScoreHash(score, duration, token, sealingNonce, sealingSecret) {
3962
+ const payload = `score:${score}|duration:${duration}|token:${token}`;
3963
+ const fullPayload = `${payload}|nonce:${sealingNonce}`;
3964
+ const encoder = new TextEncoder();
3965
+ const keyData = encoder.encode(sealingSecret);
3966
+ const messageData = encoder.encode(fullPayload);
3967
+ const cryptoKey = await crypto.subtle.importKey(
3968
+ "raw",
3969
+ keyData,
3970
+ { name: "HMAC", hash: HASH_ALGORITHM_WEB_CRYPTO },
3971
+ false,
3972
+ ["sign"]
3973
+ );
3974
+ const signature = await crypto.subtle.sign("HMAC", cryptoKey, messageData);
3975
+ return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
3976
+ }
3977
+
3979
3978
  // src/leaderboard/RpcLeaderboardApi.ts
3980
3979
  var RpcLeaderboardApi = class {
3981
3980
  constructor(rpcClient) {
3982
3981
  __publicField(this, "rpcClient");
3982
+ /** Cache of score tokens for automatic hash computation */
3983
+ __publicField(this, "tokenCache", /* @__PURE__ */ new Map());
3983
3984
  this.rpcClient = rpcClient;
3984
3985
  }
3985
- startRun(mode) {
3986
- return this.rpcClient.call(
3987
- "H5_LEADERBOARD_START_RUN" /* H5_LEADERBOARD_START_RUN */,
3986
+ /**
3987
+ * Create a score token for submitting a score.
3988
+ * Token is cached for automatic hash computation if score sealing is enabled.
3989
+ *
3990
+ * @param mode - Optional game mode
3991
+ * @returns Score token with sealing data if enabled
3992
+ */
3993
+ async createScoreToken(mode) {
3994
+ const token = await this.rpcClient.call(
3995
+ "H5_LEADERBOARD_CREATE_SCORE_TOKEN" /* H5_LEADERBOARD_CREATE_SCORE_TOKEN */,
3988
3996
  mode ? { mode } : {}
3989
3997
  );
3998
+ this.tokenCache.set(token.token, token);
3999
+ return token;
3990
4000
  }
3991
- submitScore(sessionId, score, durationSec, options) {
4001
+ /**
4002
+ * Submit a score to the leaderboard.
4003
+ * Automatically computes hash if score sealing is enabled and token was created via createScoreToken().
4004
+ *
4005
+ * @param params - Score submission parameters
4006
+ * @returns Submission result with acceptance status and rank
4007
+ * @throws Error if token not found in cache
4008
+ */
4009
+ async submitScore(params) {
4010
+ let hash;
4011
+ if (params.token) {
4012
+ const cachedToken = this.tokenCache.get(params.token);
4013
+ if (!cachedToken) {
4014
+ throw new Error(
4015
+ "Invalid token: not found in cache. Did you call createScoreToken() first?"
4016
+ );
4017
+ }
4018
+ if (cachedToken.sealingNonce && cachedToken.sealingSecret) {
4019
+ hash = await computeScoreHash(
4020
+ params.score,
4021
+ params.duration,
4022
+ params.token,
4023
+ cachedToken.sealingNonce,
4024
+ cachedToken.sealingSecret
4025
+ );
4026
+ }
4027
+ this.tokenCache.delete(params.token);
4028
+ }
3992
4029
  return this.rpcClient.call(
3993
4030
  "H5_LEADERBOARD_SUBMIT_SCORE" /* H5_LEADERBOARD_SUBMIT_SCORE */,
3994
4031
  {
3995
- sessionId,
3996
- score,
3997
- durationSec,
3998
- mode: options?.mode,
3999
- telemetry: options?.telemetry,
4000
- metadata: options?.metadata,
4001
- hash: options?.hash
4032
+ token: params.token,
4033
+ score: params.score,
4034
+ duration: params.duration,
4035
+ mode: params.mode,
4036
+ telemetry: params.telemetry,
4037
+ metadata: params.metadata,
4038
+ hash
4039
+ // undefined if no sealing, computed if sealing enabled
4002
4040
  }
4003
4041
  );
4004
4042
  }
4005
- getLeaderboard(options) {
4043
+ getPagedScores(options) {
4006
4044
  return this.rpcClient.call(
4007
- "H5_LEADERBOARD_GET" /* H5_LEADERBOARD_GET */,
4045
+ "H5_LEADERBOARD_GET_PAGED_SCORES" /* H5_LEADERBOARD_GET_PAGED_SCORES */,
4008
4046
  options ?? {}
4009
4047
  );
4010
4048
  }
4011
- getPlayerStats(options) {
4049
+ getMyRank(options) {
4012
4050
  return this.rpcClient.call(
4013
- "H5_LEADERBOARD_GET_PLAYER_STATS" /* H5_LEADERBOARD_GET_PLAYER_STATS */,
4051
+ "H5_LEADERBOARD_GET_MY_RANK" /* H5_LEADERBOARD_GET_MY_RANK */,
4014
4052
  options ?? {}
4015
4053
  );
4016
4054
  }
4017
- getLeaderboardHighlight(options) {
4055
+ getPodiumScores(options) {
4018
4056
  return this.rpcClient.call(
4019
- "H5_LEADERBOARD_GET_HIGHLIGHT" /* H5_LEADERBOARD_GET_HIGHLIGHT */,
4057
+ "H5_LEADERBOARD_GET_PODIUM_SCORES" /* H5_LEADERBOARD_GET_PODIUM_SCORES */,
4020
4058
  options ?? {}
4021
4059
  );
4022
4060
  }
@@ -4025,17 +4063,31 @@ var RpcLeaderboardApi = class {
4025
4063
  // src/leaderboard/MockLeaderboardApi.ts
4026
4064
  var MockLeaderboardApi = class {
4027
4065
  constructor(options) {
4028
- __publicField(this, "sessions", /* @__PURE__ */ new Map());
4066
+ __publicField(this, "tokens", /* @__PURE__ */ new Map());
4067
+ /** Cache of score tokens for automatic hash computation */
4068
+ __publicField(this, "tokenCache", /* @__PURE__ */ new Map());
4029
4069
  __publicField(this, "entriesByMode", /* @__PURE__ */ new Map());
4030
- __publicField(this, "sessionCounter", 0);
4031
- __publicField(this, "requiresHash", false);
4032
- if (options?.requiresHash) {
4033
- this.requiresHash = true;
4070
+ __publicField(this, "tokenCounter", 0);
4071
+ __publicField(this, "enableScoreSealing", false);
4072
+ __publicField(this, "scoreSealingSecret", "mock-leaderboard-secret-key");
4073
+ if (options?.enableScoreSealing) {
4074
+ this.enableScoreSealing = true;
4075
+ }
4076
+ if (options?.scoreSealingSecret) {
4077
+ this.scoreSealingSecret = options.scoreSealingSecret;
4034
4078
  }
4035
4079
  }
4080
+ /**
4081
+ * Configure mock leaderboard settings
4082
+ *
4083
+ * @param options - Configuration options
4084
+ */
4036
4085
  configure(options) {
4037
- if (typeof options.requiresHash === "boolean") {
4038
- this.requiresHash = options.requiresHash;
4086
+ if (typeof options.enableScoreSealing === "boolean") {
4087
+ this.enableScoreSealing = options.enableScoreSealing;
4088
+ }
4089
+ if (options.scoreSealingSecret) {
4090
+ this.scoreSealingSecret = options.scoreSealingSecret;
4039
4091
  }
4040
4092
  }
4041
4093
  generateNonce() {
@@ -4052,83 +4104,149 @@ var MockLeaderboardApi = class {
4052
4104
  }
4053
4105
  return this.entriesByMode.get(key);
4054
4106
  }
4055
- async startRun(mode) {
4056
- const sessionId = `mock_session_${++this.sessionCounter}`;
4107
+ /**
4108
+ * Create a mock score token for testing.
4109
+ * Token is cached for automatic hash computation if score sealing is enabled.
4110
+ *
4111
+ * @param mode - Optional game mode
4112
+ * @returns Score token with sealing data if enabled
4113
+ */
4114
+ async createScoreToken(mode) {
4115
+ const token = `mock_token_${++this.tokenCounter}`;
4057
4116
  const startTime = Date.now();
4058
4117
  const expiresAt = startTime + 36e5;
4059
4118
  const resolvedMode = mode || "default";
4060
- const hashNonce = this.requiresHash ? this.generateNonce() : null;
4061
- this.sessions.set(sessionId, {
4062
- id: sessionId,
4119
+ const sealingNonce = this.enableScoreSealing ? this.generateNonce() : null;
4120
+ const sealingSecret = this.enableScoreSealing ? this.scoreSealingSecret : null;
4121
+ this.tokens.set(token, {
4122
+ id: token,
4063
4123
  expiresAt,
4064
4124
  mode: resolvedMode,
4065
- hashNonce,
4125
+ sealingNonce,
4066
4126
  used: false
4067
4127
  });
4068
- return {
4069
- sessionId,
4128
+ const result = {
4129
+ token,
4070
4130
  startTime,
4071
4131
  expiresAt,
4072
- hashNonce,
4132
+ sealingNonce,
4133
+ sealingSecret,
4073
4134
  mode: resolvedMode
4074
4135
  };
4136
+ this.tokenCache.set(token, result);
4137
+ return result;
4075
4138
  }
4076
- async submitScore(sessionId, score, durationSec, options) {
4077
- const session = this.sessions.get(sessionId);
4078
- if (!session) {
4079
- throw new Error("Invalid leaderboard session");
4139
+ /**
4140
+ * Submit a mock score to the leaderboard.
4141
+ * Automatically computes hash if score sealing is enabled and token was created via createScoreToken().
4142
+ *
4143
+ * @param params - Score submission parameters
4144
+ * @returns Submission result with acceptance status and rank
4145
+ * @throws Error if token not found in cache or validation fails
4146
+ */
4147
+ async submitScore(params) {
4148
+ let hash;
4149
+ if (params.token) {
4150
+ const cachedToken = this.tokenCache.get(params.token);
4151
+ if (!cachedToken) {
4152
+ throw new Error(
4153
+ "Invalid token: not found in cache. Did you call createScoreToken() first?"
4154
+ );
4155
+ }
4156
+ if (cachedToken.sealingNonce && cachedToken.sealingSecret) {
4157
+ hash = await computeScoreHash(
4158
+ params.score,
4159
+ params.duration,
4160
+ params.token,
4161
+ cachedToken.sealingNonce,
4162
+ cachedToken.sealingSecret
4163
+ );
4164
+ }
4165
+ }
4166
+ if (!params.token) {
4167
+ const mode = params.mode || "default";
4168
+ const submittedAt2 = Date.now();
4169
+ const entry2 = {
4170
+ profileId: `mock_profile`,
4171
+ username: "Mock Player",
4172
+ avatarUrl: null,
4173
+ score: params.score,
4174
+ duration: params.duration,
4175
+ submittedAt: submittedAt2,
4176
+ token: "simple-mode",
4177
+ rank: null,
4178
+ zScore: null,
4179
+ isAnomaly: false,
4180
+ trustScore: 50,
4181
+ metadata: params.metadata ?? null,
4182
+ isSeed: false
4183
+ };
4184
+ const modeEntries2 = this.getEntriesForMode(mode);
4185
+ modeEntries2.push(entry2);
4186
+ modeEntries2.sort((a, b) => {
4187
+ if (b.score !== a.score) return b.score - a.score;
4188
+ return a.submittedAt - b.submittedAt;
4189
+ });
4190
+ modeEntries2.forEach((e, index) => {
4191
+ modeEntries2[index] = { ...e, rank: index + 1 };
4192
+ });
4193
+ const inserted2 = modeEntries2.find((e) => e.submittedAt === submittedAt2);
4194
+ return {
4195
+ accepted: true,
4196
+ rank: inserted2?.rank ?? null
4197
+ };
4080
4198
  }
4081
- if (session.expiresAt < Date.now()) {
4082
- throw new Error("Invalid or expired leaderboard session");
4199
+ const scoreToken = this.tokens.get(params.token);
4200
+ if (!scoreToken) {
4201
+ throw new Error("Invalid score token");
4083
4202
  }
4084
- if (session.used) {
4085
- throw new Error("Leaderboard session already used");
4203
+ if (scoreToken.expiresAt < Date.now()) {
4204
+ throw new Error("Invalid or expired score token");
4086
4205
  }
4087
- if (options?.mode && options.mode !== session.mode) {
4088
- throw new Error("Submission mode does not match session mode");
4206
+ if (scoreToken.used) {
4207
+ throw new Error("Score token already used");
4089
4208
  }
4090
- if (session.hashNonce && !options?.hash) {
4091
- throw new Error("Score hash is required for sealed leaderboard submissions");
4209
+ if (params.mode && params.mode !== scoreToken.mode) {
4210
+ throw new Error("Submission mode does not match token mode");
4211
+ }
4212
+ if (scoreToken.sealingNonce && !hash) {
4213
+ throw new Error("Score hash required when score sealing is enabled");
4092
4214
  }
4093
4215
  const submittedAt = Date.now();
4094
4216
  const entry = {
4095
4217
  profileId: `mock_profile`,
4096
4218
  username: "Mock Player",
4097
4219
  avatarUrl: null,
4098
- score,
4099
- durationSec,
4220
+ score: params.score,
4221
+ duration: params.duration,
4100
4222
  submittedAt,
4101
- sessionId,
4223
+ token: params.token,
4102
4224
  rank: null,
4103
4225
  zScore: null,
4104
4226
  isAnomaly: false,
4105
4227
  trustScore: 50,
4106
- metadata: options?.metadata ?? null,
4228
+ metadata: params.metadata ?? null,
4107
4229
  isSeed: false
4108
4230
  };
4109
- const modeEntries = this.getEntriesForMode(session.mode);
4231
+ const modeEntries = this.getEntriesForMode(scoreToken.mode);
4110
4232
  modeEntries.push(entry);
4111
4233
  modeEntries.sort((a, b) => {
4112
- if (b.score !== a.score) {
4113
- return b.score - a.score;
4114
- }
4234
+ if (b.score !== a.score) return b.score - a.score;
4115
4235
  return a.submittedAt - b.submittedAt;
4116
4236
  });
4117
4237
  modeEntries.forEach((e, index) => {
4118
- modeEntries[index] = {
4119
- ...e,
4120
- rank: index + 1
4121
- };
4238
+ modeEntries[index] = { ...e, rank: index + 1 };
4122
4239
  });
4123
- session.used = true;
4124
- session.hashNonce = null;
4125
- const inserted = modeEntries.find((e) => e.sessionId === sessionId && e.submittedAt === submittedAt);
4240
+ scoreToken.used = true;
4241
+ scoreToken.sealingNonce = null;
4242
+ this.tokenCache.delete(params.token);
4243
+ const inserted = modeEntries.find((e) => e.token === params.token && e.submittedAt === submittedAt);
4126
4244
  return {
4127
4245
  accepted: true,
4128
4246
  rank: inserted?.rank ?? null
4129
4247
  };
4130
4248
  }
4131
- async getLeaderboard(options) {
4249
+ async getPagedScores(options) {
4132
4250
  const limit = options?.limit ?? 10;
4133
4251
  const mode = options?.mode ?? "default";
4134
4252
  const modeEntries = [...this.getEntriesForMode(mode)];
@@ -4144,7 +4262,7 @@ var MockLeaderboardApi = class {
4144
4262
  periodInstance: options?.period ?? "alltime"
4145
4263
  };
4146
4264
  }
4147
- async getPlayerStats(_options) {
4265
+ async getMyRank(_options) {
4148
4266
  const mode = _options?.mode ?? "default";
4149
4267
  const modeEntries = this.getEntriesForMode(mode);
4150
4268
  const playerEntry = modeEntries[0] ?? null;
@@ -4157,7 +4275,7 @@ var MockLeaderboardApi = class {
4157
4275
  periodInstance: _options?.period ?? "alltime"
4158
4276
  };
4159
4277
  }
4160
- async getLeaderboardHighlight(options) {
4278
+ async getPodiumScores(options) {
4161
4279
  const mode = options?.mode ?? "default";
4162
4280
  const modeEntries = [...this.getEntriesForMode(mode)];
4163
4281
  const topCount = Math.max(1, Math.min(options?.topCount ?? 3, 10));
@@ -5706,6 +5824,174 @@ function initializeLoggingApi(venusApi, host) {
5706
5824
  var BurgerTimeAssetsCdnPath = "burger-time/Core.stow";
5707
5825
  var CharacterAssetsCdnPath = "burger-time/Character.stow";
5708
5826
 
5827
+ // src/shared-assets/embeddedLibrariesManifest.ts
5828
+ var EMBEDDED_LIBRARIES = [
5829
+ {
5830
+ libraryKey: "phaser@3.90.0",
5831
+ assetKey: "library:phaser@3.90.0",
5832
+ packageName: "phaser",
5833
+ version: "3.90.0",
5834
+ globalVar: "Phaser",
5835
+ cdnPath: "phaser/3.90.0/phaser.min.js",
5836
+ moduleSpecifiers: [{ match: "exact", value: "phaser" }],
5837
+ loadStage: 0,
5838
+ enabled: true
5839
+ },
5840
+ {
5841
+ libraryKey: "react@18.3.1",
5842
+ assetKey: "library:react@18.3.1",
5843
+ packageName: "react",
5844
+ version: "18.3.1",
5845
+ globalVar: "React",
5846
+ cdnPath: "react/18.3.1/react.production.min.js",
5847
+ moduleSpecifiers: [
5848
+ { match: "exact", value: "react", behavior: "namespace" },
5849
+ { match: "exact", value: "react/jsx-runtime", behavior: "react-jsx-runtime" },
5850
+ {
5851
+ match: "exact",
5852
+ value: "react/jsx-dev-runtime",
5853
+ behavior: "react-jsx-dev-runtime"
5854
+ }
5855
+ ],
5856
+ loadStage: 0,
5857
+ // Must load before ReactDOM
5858
+ enabled: true
5859
+ },
5860
+ {
5861
+ libraryKey: "react-dom@18.3.1",
5862
+ assetKey: "library:react-dom@18.3.1",
5863
+ packageName: "react-dom",
5864
+ version: "18.3.1",
5865
+ globalVar: "ReactDOM",
5866
+ cdnPath: "react-dom/18.3.1/react-dom.production.min.js",
5867
+ moduleSpecifiers: [
5868
+ { match: "exact", value: "react-dom", behavior: "namespace" },
5869
+ { match: "exact", value: "react-dom/client", behavior: "namespace" }
5870
+ ],
5871
+ loadStage: 1,
5872
+ // Depends on React (stage 0)
5873
+ enabled: true
5874
+ },
5875
+ {
5876
+ libraryKey: "three@0.170.0",
5877
+ assetKey: "library:three@0.170.0",
5878
+ packageName: "three",
5879
+ version: "0.170.0",
5880
+ globalVar: "THREE",
5881
+ cdnPath: "three/r170/three.min.js",
5882
+ moduleSpecifiers: [
5883
+ { match: "exact", value: "three", behavior: "namespace" },
5884
+ { match: "prefix", value: "three/examples/jsm/", behavior: "namespace" }
5885
+ ],
5886
+ loadStage: 0,
5887
+ enabled: true
5888
+ },
5889
+ {
5890
+ libraryKey: "matter-js@0.19.0",
5891
+ assetKey: "library:matter-js@0.19.0",
5892
+ packageName: "matter-js",
5893
+ version: "0.19.0",
5894
+ globalVar: "Matter",
5895
+ cdnPath: "matter-js/0.19.0/matter.min.js",
5896
+ moduleSpecifiers: [{ match: "exact", value: "matter-js" }],
5897
+ loadStage: 0,
5898
+ enabled: true
5899
+ },
5900
+ {
5901
+ libraryKey: "inkjs@2.2.0",
5902
+ assetKey: "library:inkjs@2.2.0",
5903
+ packageName: "inkjs",
5904
+ version: "2.2.0",
5905
+ globalVar: "inkjs",
5906
+ cdnPath: "inkjs/2.2.0/ink.min.js",
5907
+ moduleSpecifiers: [{ match: "exact", value: "inkjs" }],
5908
+ loadStage: 0,
5909
+ enabled: true
5910
+ },
5911
+ {
5912
+ libraryKey: "zustand@5.0.3",
5913
+ assetKey: "library:zustand@5.0.3",
5914
+ packageName: "zustand",
5915
+ version: "5.0.3",
5916
+ globalVar: "zustand",
5917
+ cdnPath: "zustand/5.0.3/zustand.min.js",
5918
+ moduleSpecifiers: [
5919
+ { match: "exact", value: "zustand" },
5920
+ { match: "exact", value: "zustand/middleware" }
5921
+ ],
5922
+ loadStage: 0,
5923
+ enabled: true
5924
+ },
5925
+ {
5926
+ libraryKey: "ammo.js@2024.11",
5927
+ assetKey: "library:ammo.js@2024.11",
5928
+ packageName: "ammo.js",
5929
+ version: "2024.11",
5930
+ globalVar: "Ammo",
5931
+ cdnPath: "ammo/2024.11/ammo.js",
5932
+ moduleSpecifiers: [
5933
+ { match: "exact", value: "ammo.js" },
5934
+ { match: "exact", value: "ammo.js/builds/ammo.wasm.js" }
5935
+ ],
5936
+ loadStage: 0,
5937
+ enabled: false
5938
+ // Not ready yet - WASM loading needs additional work
5939
+ }
5940
+ ];
5941
+ var EMBEDDED_LIBRARY_BY_KEY = EMBEDDED_LIBRARIES.reduce(
5942
+ (acc, lib) => {
5943
+ acc[lib.libraryKey] = lib;
5944
+ return acc;
5945
+ },
5946
+ {}
5947
+ );
5948
+ EMBEDDED_LIBRARIES.filter(
5949
+ (lib) => lib.enabled
5950
+ ).flatMap(
5951
+ (lib) => lib.moduleSpecifiers.map((specifier) => ({
5952
+ ...specifier,
5953
+ libraryKey: lib.libraryKey
5954
+ }))
5955
+ );
5956
+ function getLibraryDefinition(libraryKey) {
5957
+ const definition = EMBEDDED_LIBRARY_BY_KEY[libraryKey];
5958
+ if (!definition) {
5959
+ const availableKeys = Object.keys(EMBEDDED_LIBRARY_BY_KEY).join(", ");
5960
+ throw new Error(
5961
+ `Unsupported embedded library: ${libraryKey}. Available libraries: ${availableKeys}`
5962
+ );
5963
+ }
5964
+ return definition;
5965
+ }
5966
+
5967
+ // src/shared-assets/base64Utils.ts
5968
+ function base64ToArrayBuffer(base64) {
5969
+ const binaryString = atob(base64);
5970
+ const len = binaryString.length;
5971
+ const bytes = new Uint8Array(len);
5972
+ for (let i = 0; i < len; i++) {
5973
+ bytes[i] = binaryString.charCodeAt(i);
5974
+ }
5975
+ return bytes.buffer;
5976
+ }
5977
+ function base64ToUtf8(base64) {
5978
+ if (typeof TextDecoder !== "undefined") {
5979
+ const decoder = new TextDecoder("utf-8");
5980
+ const buffer = base64ToArrayBuffer(base64);
5981
+ return decoder.decode(new Uint8Array(buffer));
5982
+ }
5983
+ if (typeof globalThis !== "undefined" && typeof globalThis.Buffer !== "undefined") {
5984
+ const BufferCtor = globalThis.Buffer;
5985
+ return BufferCtor.from(base64, "base64").toString("utf-8");
5986
+ }
5987
+ const binaryString = atob(base64);
5988
+ let result = "";
5989
+ for (let i = 0; i < binaryString.length; i++) {
5990
+ result += String.fromCharCode(binaryString.charCodeAt(i));
5991
+ }
5992
+ return decodeURIComponent(escape(result));
5993
+ }
5994
+
5709
5995
  // src/shared-assets/RpcSharedAssetsApi.ts
5710
5996
  var RpcSharedAssetsApi = class {
5711
5997
  constructor(rpcClient, venusApi) {
@@ -5744,16 +6030,33 @@ var RpcSharedAssetsApi = class {
5744
6030
  }
5745
6031
  }
5746
6032
  }
5747
- };
5748
- function base64ToArrayBuffer(base64) {
5749
- const binaryString = atob(base64);
5750
- const len = binaryString.length;
5751
- const bytes = new Uint8Array(len);
5752
- for (let i = 0; i < len; i++) {
5753
- bytes[i] = binaryString.charCodeAt(i);
6033
+ async loadLibraryCode(libraryKey) {
6034
+ const definition = getLibraryDefinition(libraryKey);
6035
+ try {
6036
+ const response = await this.rpcClient.callT("H5_LOAD_EMBEDDED_ASSET" /* H5_LOAD_EMBEDDED_ASSET */, {
6037
+ assetKey: definition.assetKey
6038
+ });
6039
+ return base64ToUtf8(response.base64Data);
6040
+ } catch (err) {
6041
+ console.error(
6042
+ `[Venus Libraries] Failed to load ${libraryKey} from host via RPC:`,
6043
+ err
6044
+ );
6045
+ console.warn(
6046
+ `[Venus Libraries] Falling back to CDN for ${libraryKey}. This may indicate an asset packaging issue.`
6047
+ );
6048
+ try {
6049
+ const cdnUrl = this.venusApi.cdn.resolveSharedLibUrl(definition.cdnPath);
6050
+ const response = await this.venusApi.cdn.fetchFromCdn(cdnUrl);
6051
+ return await response.text();
6052
+ } catch (cdnError) {
6053
+ throw new Error(
6054
+ `Failed to load embedded library ${libraryKey}: RPC failed, CDN fallback failed: ${cdnError.message}`
6055
+ );
6056
+ }
6057
+ }
5754
6058
  }
5755
- return bytes.buffer;
5756
- }
6059
+ };
5757
6060
 
5758
6061
  // src/shared-assets/MockSharedAssetsApi.ts
5759
6062
  var MockSharedAssetsApi = class {
@@ -5769,6 +6072,12 @@ var MockSharedAssetsApi = class {
5769
6072
  const blob = await this.venusApi.cdn.fetchBlob(CharacterAssetsCdnPath);
5770
6073
  return await blob.arrayBuffer();
5771
6074
  }
6075
+ async loadLibraryCode(libraryKey) {
6076
+ const definition = getLibraryDefinition(libraryKey);
6077
+ const url = this.venusApi.cdn.resolveSharedLibUrl(definition.cdnPath);
6078
+ const response = await this.venusApi.cdn.fetchFromCdn(url);
6079
+ return await response.text();
6080
+ }
5772
6081
  };
5773
6082
 
5774
6083
  // src/game-preloader/MockPreloaderApi.ts
@@ -7134,7 +7443,7 @@ var RemoteHost = class {
7134
7443
  this.popups = new RpcPopupsApi(rpcClient);
7135
7444
  this.profile = new HostProfileApi();
7136
7445
  this.cdn = new HostCdnApi(getCdnBaseUrl());
7137
- this.time = new HostTimeApi(rpcClient);
7446
+ this.time = new HostTimeApi(rpcClient, venusApi);
7138
7447
  this.post = new RpcPostApi(rpcClient);
7139
7448
  this.ai = new RpcAiApi(rpcClient);
7140
7449
  this.haptics = new RpcHapticsApi(rpcClient);
@@ -7221,7 +7530,7 @@ function createHost(venusApi, isMock) {
7221
7530
  init_rooms();
7222
7531
 
7223
7532
  // src/version.ts
7224
- var SDK_VERSION = "3.0.4";
7533
+ var SDK_VERSION = "3.1.0-beta.0";
7225
7534
 
7226
7535
  // src/social/index.ts
7227
7536
  function initializeSocial(venusApi, host) {
@@ -7527,6 +7836,26 @@ var VenusAPI2 = class {
7527
7836
  }
7528
7837
  }
7529
7838
  });
7839
+ const originalConfig = this.config;
7840
+ this.config = new Proxy(originalConfig, {
7841
+ get(target, prop) {
7842
+ if (prop === "locale" || prop === "languageCode") {
7843
+ console.error(
7844
+ `[Venus SDK] config.${prop} is deprecated and will be removed in v4.0.0. Use VenusAPI.${prop === "locale" ? "getLocale()" : "getLanguageCode()"}() instead.`
7845
+ );
7846
+ }
7847
+ return target[prop];
7848
+ },
7849
+ set(target, prop, value) {
7850
+ if (prop === "locale" || prop === "languageCode") {
7851
+ console.error(
7852
+ `[Venus SDK] config.${prop} is deprecated and will be removed in v4.0.0. Use VenusAPI.${prop === "locale" ? "getLocale()" : "getLanguageCode()"}() instead.`
7853
+ );
7854
+ }
7855
+ target[prop] = value;
7856
+ return true;
7857
+ }
7858
+ });
7530
7859
  const isInsideHostedEnv = this._bootstrap.isInsideHostedEnvironment;
7531
7860
  const host = createHost(this, !isInsideHostedEnv);
7532
7861
  this.host = host;
@@ -7557,6 +7886,28 @@ var VenusAPI2 = class {
7557
7886
  initializeSimulation(this, host);
7558
7887
  initializeSocial(this, host);
7559
7888
  initializeAssetLoader(this, createProxiedMethod);
7889
+ this.getLocale = () => {
7890
+ if (typeof window !== "undefined" && window.venus) {
7891
+ const venus = window.venus;
7892
+ if (venus.config && venus.config.locale) {
7893
+ return venus.config.locale;
7894
+ }
7895
+ if (venus._config && venus._config.locale) {
7896
+ return venus._config.locale;
7897
+ }
7898
+ if (venus.config?.environment?.browserInfo?.language) {
7899
+ return venus.config.environment.browserInfo.language;
7900
+ }
7901
+ }
7902
+ if (typeof navigator !== "undefined" && navigator.language) {
7903
+ return navigator.language;
7904
+ }
7905
+ return "en-US";
7906
+ };
7907
+ this.getLanguageCode = () => {
7908
+ const locale = this.getLocale();
7909
+ return locale.split("-")[0];
7910
+ };
7560
7911
  }
7561
7912
  // Generate deterministic instance ID based on current page URL
7562
7913
  _generateDeterministicInstanceId() {