@series-inc/venus-sdk 3.4.3-beta.4 → 3.4.3-beta.6

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.
@@ -609,6 +609,33 @@ interface VenusRoomPayload extends Record<string, unknown> {
609
609
  data?: Record<string, unknown>;
610
610
  version?: number;
611
611
  }
612
+ /**
613
+ * Server API response envelopes.
614
+ * These match the format returned by the H5 Rooms Cloud Functions.
615
+ */
616
+ /**
617
+ * Standard envelope for endpoints that return a single room.
618
+ */
619
+ interface RoomEnvelopeResponse {
620
+ success: boolean;
621
+ room: VenusRoomPayload;
622
+ }
623
+ /**
624
+ * Standard envelope for endpoints that return multiple rooms.
625
+ */
626
+ interface RoomsEnvelopeResponse {
627
+ success: boolean;
628
+ rooms: VenusRoomPayload[];
629
+ }
630
+ /**
631
+ * Standard envelope for join-or-create room endpoint.
632
+ */
633
+ interface JoinOrCreateRoomEnvelopeResponse {
634
+ success: boolean;
635
+ action: 'created' | 'joined';
636
+ room: VenusRoomPayload;
637
+ playersJoined: number;
638
+ }
612
639
  declare class VenusRoom {
613
640
  readonly id: string;
614
641
  name?: string;
@@ -1635,4 +1662,4 @@ interface AdsApi {
1635
1662
  showInterstitialAd(options?: ShowInterstitialAdOptions): Promise<boolean>;
1636
1663
  }
1637
1664
 
1638
- export { type AiApi as $, type AnalyticsApi as A, type BatchRecipeRequirementsResult as B, type ScheduleNotificationOptions as C, type PopupsApi as D, type ShowToastOptions as E, type ShowInterstitialAdOptions as F, type ShowRewardedAdOptions as G, type Host as H, type ProfileApi as I, type DeviceApi as J, type DeviceInfo as K, type EnvironmentApi as L, type EnvironmentInfo as M, type NavigationApi as N, type SystemApi as O, type Profile as P, type QuitOptions as Q, type RecipeRequirementResult as R, type SimulationRunSummary as S, type SafeArea as T, type CdnApi as U, type VenusAPI as V, type SubPath as W, type FetchBlobOptions as X, type TimeApi as Y, type ServerTimeData as Z, type GetFutureTimeOptions as _, type VenusSimulationStateResponse as a, type PlayerRankResult as a$, type AiChatCompletionRequest as a0, type AiChatCompletionData as a1, type HapticsApi as a2, HapticFeedbackStyle as a3, type FeaturesApi as a4, type Experiment as a5, type LifecycleApi as a6, type SleepCallback as a7, type Subscription as a8, type AwakeCallback as a9, type ProposedMoveEvent as aA, VenusTransport as aB, type RoomsApi as aC, type CreateRoomOptions as aD, type JoinOrCreateRoomOptions as aE, type JoinOrCreateResult as aF, type ListRoomsOptions as aG, type UpdateRoomDataOptions as aH, type RoomMessageRequest as aI, type StartRoomGameOptions as aJ, type ProposeMoveRequest as aK, type ProposeMoveResult as aL, type ValidateMoveVerdict as aM, type ValidateMoveResult as aN, type RoomSubscriptionOptions as aO, type LoggingApi as aP, type IapApi as aQ, type SpendCurrencyOptions as aR, type LoadEmbeddedAssetsResponse as aS, type SharedAssetsApi as aT, type LeaderboardApi as aU, type ScoreToken as aV, type SubmitScoreParams as aW, type SubmitScoreResult as aX, type GetPagedScoresOptions as aY, type PagedScoresResponse as aZ, type PlayerRankOptions as a_, type PauseCallback as aa, type ResumeCallback as ab, type QuitCallback as ac, type SimulationApi as ad, type SimulationSlotValidationResult as ae, type SimulationBatchOperation as af, type SimulationBatchOperationsResult as ag, type SimulationAvailableItem as ah, type SimulationPowerPreview as ai, type SimulationSlotMutationResult as aj, type SimulationSlotContainer as ak, type SimulationAssignment as al, type SimulationState as am, type ExecuteRecipeOptions as an, type ExecuteRecipeResponse as ao, type CollectRecipeResult as ap, type GetActiveRunsOptions as aq, type ExecuteScopedRecipeOptions as ar, type ExecuteScopedRecipeResult as as, type GetAvailableRecipesOptions as at, type GetAvailableRecipesResult as au, type Recipe as av, type GetBatchRecipeRequirements as aw, type TriggerRecipeChainOptions as ax, type RoomDataUpdate as ay, type RoomMessageEvent as az, type SimulationUpdateType as b, type GetPodiumScoresOptions as b0, type PodiumScoresResponse as b1, type PreloaderApi as b2, type SocialApi as b3, type ShareMetadata as b4, type ShareLinkResult as b5, type SocialQRCodeOptions as b6, type QRCodeResult as b7, type Avatar3dApi as b8, type AssetManifest as b9, type RecipeInfo as bA, type SimulationPersonalState as bB, type SimulationRoomActiveRecipe as bC, type SimulationRoomState as bD, type SimulationBatchOperationAssign as bE, type SimulationBatchOperationRemove as bF, type SimulationBatchOperationResult as bG, RpcSharedAssetsApi as bH, type LoadEmbeddedAssetsRequest as bI, type LeaderboardModeConfig as bJ, type LeaderboardPeriodType as bK, type LeaderboardPeriodConfig as bL, type LeaderboardAntiCheatConfig as bM, type LeaderboardDisplaySettings as bN, type LeaderboardConfig as bO, type LeaderboardEntry as bP, type PodiumScoresContext as bQ, type HudInsets as bR, createHost as bS, type Avatar3dConfig as ba, type ShowEditorOptions as bb, type Avatar3dEdits as bc, type AdsApi as bd, type InitializationContext as be, type InitializationOptions as bf, type AiMessage as bg, type Asset as bh, type Category as bi, MockAvatarApi as bj, type TimeIntervalTriggerInput as bk, type NotificationTriggerInput as bl, type OnRequestCallback as bm, type OnResponseCallback as bn, type OnNotificationCallback as bo, type RpcTransport as bp, type JoinRoomMatchCriteria as bq, type RoomMessageEventType as br, type RoomMessagePayload as bs, type ProposedMovePayload as bt, ROOM_GAME_PHASES as bu, type RoomGamePhase as bv, type VenusRoomRulesGameState as bw, type VenusRoomRules as bx, type VenusRoomCustomMetadata as by, type VenusRoomPayload as bz, type SimulationEntityUpdate as c, type SimulationActiveRunsUpdate as d, type SimulationSnapshotUpdate as e, type SimulationUpdateData as f, type SimulationSubscribeOptions as g, type VenusSimulationEffect as h, type VenusSimulationRecipe as i, type VenusSimulationConfig as j, type RecipeRequirementQuery as k, type VenusExecuteRecipeOptions as l, type VenusExecuteScopedRecipeOptions as m, type VenusAvailableRecipe as n, type VenusCollectRecipeResult as o, type VenusExecuteRecipeResult as p, VenusRoom as q, type RpcRequest as r, type RpcResponse as s, type RpcNotification as t, RpcClient as u, type StorageApi as v, type NavigationStackInfo as w, type PushAppOptions as x, type NotificationsApi as y, type ScheduleLocalNotification as z };
1665
+ export { type AiApi as $, type AnalyticsApi as A, type BatchRecipeRequirementsResult as B, type ScheduleNotificationOptions as C, type PopupsApi as D, type ShowToastOptions as E, type ShowInterstitialAdOptions as F, type ShowRewardedAdOptions as G, type Host as H, type ProfileApi as I, type DeviceApi as J, type DeviceInfo as K, type EnvironmentApi as L, type EnvironmentInfo as M, type NavigationApi as N, type SystemApi as O, type Profile as P, type QuitOptions as Q, type RecipeRequirementResult as R, type SimulationRunSummary as S, type SafeArea as T, type CdnApi as U, type VenusAPI as V, type SubPath as W, type FetchBlobOptions as X, type TimeApi as Y, type ServerTimeData as Z, type GetFutureTimeOptions as _, type VenusSimulationStateResponse as a, type PlayerRankResult as a$, type AiChatCompletionRequest as a0, type AiChatCompletionData as a1, type HapticsApi as a2, HapticFeedbackStyle as a3, type FeaturesApi as a4, type Experiment as a5, type LifecycleApi as a6, type SleepCallback as a7, type Subscription as a8, type AwakeCallback as a9, type ProposedMoveEvent as aA, VenusTransport as aB, type RoomsApi as aC, type CreateRoomOptions as aD, type JoinOrCreateRoomOptions as aE, type JoinOrCreateResult as aF, type ListRoomsOptions as aG, type UpdateRoomDataOptions as aH, type RoomMessageRequest as aI, type StartRoomGameOptions as aJ, type ProposeMoveRequest as aK, type ProposeMoveResult as aL, type ValidateMoveVerdict as aM, type ValidateMoveResult as aN, type RoomSubscriptionOptions as aO, type LoggingApi as aP, type IapApi as aQ, type SpendCurrencyOptions as aR, type LoadEmbeddedAssetsResponse as aS, type SharedAssetsApi as aT, type LeaderboardApi as aU, type ScoreToken as aV, type SubmitScoreParams as aW, type SubmitScoreResult as aX, type GetPagedScoresOptions as aY, type PagedScoresResponse as aZ, type PlayerRankOptions as a_, type PauseCallback as aa, type ResumeCallback as ab, type QuitCallback as ac, type SimulationApi as ad, type SimulationSlotValidationResult as ae, type SimulationBatchOperation as af, type SimulationBatchOperationsResult as ag, type SimulationAvailableItem as ah, type SimulationPowerPreview as ai, type SimulationSlotMutationResult as aj, type SimulationSlotContainer as ak, type SimulationAssignment as al, type SimulationState as am, type ExecuteRecipeOptions as an, type ExecuteRecipeResponse as ao, type CollectRecipeResult as ap, type GetActiveRunsOptions as aq, type ExecuteScopedRecipeOptions as ar, type ExecuteScopedRecipeResult as as, type GetAvailableRecipesOptions as at, type GetAvailableRecipesResult as au, type Recipe as av, type GetBatchRecipeRequirements as aw, type TriggerRecipeChainOptions as ax, type RoomDataUpdate as ay, type RoomMessageEvent as az, type SimulationUpdateType as b, type GetPodiumScoresOptions as b0, type PodiumScoresResponse as b1, type PreloaderApi as b2, type SocialApi as b3, type ShareMetadata as b4, type ShareLinkResult as b5, type SocialQRCodeOptions as b6, type QRCodeResult as b7, type Avatar3dApi as b8, type AssetManifest as b9, type RoomEnvelopeResponse as bA, type RoomsEnvelopeResponse as bB, type JoinOrCreateRoomEnvelopeResponse as bC, type RecipeInfo as bD, type SimulationPersonalState as bE, type SimulationRoomActiveRecipe as bF, type SimulationRoomState as bG, type SimulationBatchOperationAssign as bH, type SimulationBatchOperationRemove as bI, type SimulationBatchOperationResult as bJ, RpcSharedAssetsApi as bK, type LoadEmbeddedAssetsRequest as bL, type LeaderboardModeConfig as bM, type LeaderboardPeriodType as bN, type LeaderboardPeriodConfig as bO, type LeaderboardAntiCheatConfig as bP, type LeaderboardDisplaySettings as bQ, type LeaderboardConfig as bR, type LeaderboardEntry as bS, type PodiumScoresContext as bT, type HudInsets as bU, createHost as bV, type Avatar3dConfig as ba, type ShowEditorOptions as bb, type Avatar3dEdits as bc, type AdsApi as bd, type InitializationContext as be, type InitializationOptions as bf, type AiMessage as bg, type Asset as bh, type Category as bi, MockAvatarApi as bj, type TimeIntervalTriggerInput as bk, type NotificationTriggerInput as bl, type OnRequestCallback as bm, type OnResponseCallback as bn, type OnNotificationCallback as bo, type RpcTransport as bp, type JoinRoomMatchCriteria as bq, type RoomMessageEventType as br, type RoomMessagePayload as bs, type ProposedMovePayload as bt, ROOM_GAME_PHASES as bu, type RoomGamePhase as bv, type VenusRoomRulesGameState as bw, type VenusRoomRules as bx, type VenusRoomCustomMetadata as by, type VenusRoomPayload as bz, type SimulationEntityUpdate as c, type SimulationActiveRunsUpdate as d, type SimulationSnapshotUpdate as e, type SimulationUpdateData as f, type SimulationSubscribeOptions as g, type VenusSimulationEffect as h, type VenusSimulationRecipe as i, type VenusSimulationConfig as j, type RecipeRequirementQuery as k, type VenusExecuteRecipeOptions as l, type VenusExecuteScopedRecipeOptions as m, type VenusAvailableRecipe as n, type VenusCollectRecipeResult as o, type VenusExecuteRecipeResult as p, VenusRoom as q, type RpcRequest as r, type RpcResponse as s, type RpcNotification as t, RpcClient as u, type StorageApi as v, type NavigationStackInfo as w, type PushAppOptions as x, type NotificationsApi as y, type ScheduleLocalNotification as z };
@@ -1,4 +1,4 @@
1
- import { MockAdsApi, MockLifecycleApi, MockAnalyticsApi, getSandboxConfig, createMockStorageApi, MockAvatarApi, MockNavigationApi, MockNotificationsApi, MockPopupsApi, SandboxProfileApi, MockDeviceApi, MockEnvironmentApi, MockSystemApi, MockCdnApi, MockTimeApi, MockAiApi, MockHapticsApi, MockFeaturesApi, MockLoggingApi, MockIapApi, MockSocialApi, initializeRoomsApi, MockPreloaderApi, MockSharedAssetsApi, VenusRoom, buildFunctionsBaseUrl } from './chunk-Z72SXERI.js';
1
+ import { MockAdsApi, MockLifecycleApi, MockAnalyticsApi, getSandboxConfig, createMockStorageApi, MockAvatarApi, MockNavigationApi, MockNotificationsApi, MockPopupsApi, SandboxProfileApi, MockDeviceApi, MockEnvironmentApi, MockSystemApi, MockCdnApi, MockTimeApi, MockAiApi, MockHapticsApi, MockFeaturesApi, MockLoggingApi, MockIapApi, MockSocialApi, initializeRoomsApi, MockPreloaderApi, MockSharedAssetsApi, VenusRoom, buildFunctionsBaseUrl } from './chunk-63XTHTEP.js';
2
2
  import './chunk-3APM3V2M.js';
3
3
 
4
4
  // src/firebase/localSandboxIdentity.ts
@@ -34,7 +34,6 @@ async function getFirebaseClient() {
34
34
  return cachedClient;
35
35
  }
36
36
  async function initializeFirebaseClient() {
37
- console.log("[Venus SDK] === FIREBASE CLIENT BUILD #4 ===");
38
37
  const config = getSandboxConfig();
39
38
  console.log("[Venus SDK] Config:", config?.target, config?.gameId);
40
39
  if (!config || !config.firebaseConfig) {
@@ -431,12 +430,18 @@ var FirestoreStorageApi = class {
431
430
  await client.setDoc(docRef, updates, { merge: true });
432
431
  }
433
432
  async removeMultipleItems(keys) {
433
+ if (keys.length === 0) {
434
+ return;
435
+ }
434
436
  const client = await this.getClient();
435
437
  const docRef = await this.getDocRef();
436
438
  const updates = {};
437
439
  for (const key of keys) {
438
440
  updates[key] = client.deleteField();
439
441
  }
442
+ if (Object.keys(updates).length === 0) {
443
+ return;
444
+ }
440
445
  try {
441
446
  await client.updateDoc(docRef, updates);
442
447
  } catch (error) {
@@ -477,9 +482,6 @@ async function callRemoteFunction(functionName, payload) {
477
482
  throw new Error(errorMessage);
478
483
  }
479
484
  const text = await response.text();
480
- if (!text || text.trim().length === 0) {
481
- return void 0;
482
- }
483
485
  try {
484
486
  return JSON.parse(text);
485
487
  } catch {
@@ -549,72 +551,121 @@ var HttpSimulationApi = class {
549
551
  let lastRunsSignature = null;
550
552
  let latestInventory = {};
551
553
  let latestRuns = [];
554
+ const requestedEntityIds = Array.isArray(options.entities) ? options.entities.filter((e) => typeof e === "string" && e.length > 0) : [];
555
+ const requestedTags = Array.isArray(options.tags) ? options.tags.filter((t) => typeof t === "string" && t.length > 0) : [];
556
+ const wantsInventory = requestedEntityIds.length > 0 || requestedTags.length > 0;
557
+ const wantsActiveRuns = Boolean(options.activeRuns);
558
+ const cleanupPartialSubscriptions = () => {
559
+ for (const unsub of unsubscribers) {
560
+ try {
561
+ unsub();
562
+ } catch (e) {
563
+ console.error("[Venus SDK] Error during simulation subscription cleanup:", e);
564
+ }
565
+ }
566
+ };
552
567
  const sendUpdate = () => {
553
568
  const snapshot = {
554
569
  type: "snapshot",
555
- entities: Object.entries(latestInventory).map(([entityId, quantity]) => ({
556
- entityId,
557
- quantity
558
- })),
559
- activeRuns: latestRuns,
560
570
  timestamp: Date.now()
561
571
  };
572
+ if (wantsInventory) {
573
+ snapshot.entities = Object.entries(latestInventory).map(([entityId, quantity]) => ({
574
+ entityId,
575
+ quantity
576
+ }));
577
+ }
578
+ if (wantsActiveRuns) {
579
+ snapshot.activeRuns = latestRuns;
580
+ }
562
581
  options.onUpdate(snapshot);
563
582
  };
564
- const statePath = roomId ? `h5_rooms/${roomId}/h5_simulation/${this.appId}` : `profiles/${this.getProfileId()}/h5_simulation/${this.appId}`;
565
- const unsubscribeState = await observeFirestoreDocument(
566
- statePath,
567
- (doc) => {
568
- const inventory = doc?.inventory ?? {};
569
- const signature = JSON.stringify(inventory);
570
- if (signature !== lastInventorySignature) {
571
- lastInventorySignature = signature;
572
- latestInventory = inventory;
573
- sendUpdate();
583
+ try {
584
+ let allowedEntityIds = null;
585
+ if (wantsInventory) {
586
+ allowedEntityIds = /* @__PURE__ */ new Set();
587
+ for (const id of requestedEntityIds) {
588
+ allowedEntityIds.add(id);
574
589
  }
575
- }
576
- );
577
- unsubscribers.push(unsubscribeState);
578
- if (options.activeRuns) {
579
- const filters = roomId ? [
580
- { field: "roomId", op: "==", value: roomId },
581
- { field: "appId", op: "==", value: this.appId },
582
- { field: "status", op: "in", value: ["running", "awaiting_collection"] }
583
- ] : [
584
- { field: "profileId", op: "==", value: this.getProfileId() },
585
- { field: "appId", op: "==", value: this.appId },
586
- { field: "status", op: "in", value: ["running", "awaiting_collection"] }
587
- ];
588
- const unsubscribeRuns = await observeFirestoreCollection(
589
- "h5_simulation_runs",
590
- {
591
- filters,
592
- orderBy: [{ field: "expiresAt", direction: "desc" }]
593
- },
594
- (docs) => {
595
- const runs = docs.map((doc) => ({
596
- id: doc.id,
597
- recipeId: doc.recipeId,
598
- status: doc.status,
599
- startTime: normalizeTimestamp(doc.startTime),
600
- expiresAt: normalizeTimestamp(doc.expiresAt),
601
- entity: doc.entity,
602
- inputs: doc.inputs,
603
- outputs: doc.outputs
604
- }));
605
- const signature = JSON.stringify(runs);
606
- if (signature !== lastRunsSignature) {
607
- lastRunsSignature = signature;
608
- latestRuns = runs;
609
- sendUpdate();
590
+ if (requestedTags.length > 0) {
591
+ const config = await this.getConfigAsync(roomId);
592
+ const requestedTagSet = new Set(requestedTags);
593
+ for (const [entityId, entityDef] of Object.entries(config.entities || {})) {
594
+ const tags = entityDef?.tags || [];
595
+ if (Array.isArray(tags) && tags.some((t) => requestedTagSet.has(t))) {
596
+ allowedEntityIds.add(entityId);
597
+ }
610
598
  }
611
599
  }
612
- );
613
- unsubscribers.push(unsubscribeRuns);
600
+ const statePath = roomId ? `h5_rooms/${roomId}/h5_simulation/${this.appId}` : `profiles/${this.getProfileId()}/h5_simulation/${this.appId}`;
601
+ const unsubscribeState = await observeFirestoreDocument(
602
+ statePath,
603
+ (doc) => {
604
+ const inventory = doc?.inventory ?? {};
605
+ const filteredInventory = {};
606
+ for (const [entityId, quantity] of Object.entries(inventory)) {
607
+ if (!allowedEntityIds || allowedEntityIds.has(entityId)) {
608
+ filteredInventory[entityId] = quantity;
609
+ }
610
+ }
611
+ const signature = JSON.stringify(filteredInventory);
612
+ if (signature !== lastInventorySignature) {
613
+ lastInventorySignature = signature;
614
+ latestInventory = filteredInventory;
615
+ sendUpdate();
616
+ }
617
+ }
618
+ );
619
+ unsubscribers.push(unsubscribeState);
620
+ }
621
+ if (wantsActiveRuns) {
622
+ const filters = roomId ? [
623
+ { field: "roomId", op: "==", value: roomId },
624
+ { field: "appId", op: "==", value: this.appId },
625
+ { field: "status", op: "in", value: ["running", "awaiting_collection"] }
626
+ ] : [
627
+ { field: "profileId", op: "==", value: this.getProfileId() },
628
+ { field: "appId", op: "==", value: this.appId },
629
+ { field: "status", op: "in", value: ["running", "awaiting_collection"] }
630
+ ];
631
+ const unsubscribeRuns = await observeFirestoreCollection(
632
+ "h5_simulation_runs",
633
+ {
634
+ filters,
635
+ orderBy: [{ field: "expiresAt", direction: "desc" }]
636
+ },
637
+ (docs) => {
638
+ const runs = docs.map((doc) => ({
639
+ id: doc.id,
640
+ recipeId: doc.recipeId,
641
+ status: doc.status,
642
+ startTime: normalizeTimestamp(doc.startTime),
643
+ expiresAt: normalizeTimestamp(doc.expiresAt),
644
+ entity: doc.entity,
645
+ inputs: doc.inputs,
646
+ outputs: doc.outputs
647
+ }));
648
+ const signature = JSON.stringify(runs);
649
+ if (signature !== lastRunsSignature) {
650
+ lastRunsSignature = signature;
651
+ latestRuns = runs;
652
+ sendUpdate();
653
+ }
654
+ }
655
+ );
656
+ unsubscribers.push(unsubscribeRuns);
657
+ }
658
+ } catch (error) {
659
+ cleanupPartialSubscriptions();
660
+ throw error;
614
661
  }
615
662
  const unsubscribe = () => {
616
663
  for (const unsub of unsubscribers) {
617
- unsub();
664
+ try {
665
+ unsub();
666
+ } catch (e) {
667
+ console.error("[Venus SDK] Error during simulation subscription cleanup:", e);
668
+ }
618
669
  }
619
670
  this.activeSubscriptions.delete(unsubscribe);
620
671
  };
@@ -947,11 +998,20 @@ var FirestoreRoomsApi = class {
947
998
  const client = await this.getClient();
948
999
  const roomRef = client.doc(client.firestore, `h5_rooms/${room.id}`);
949
1000
  const merge = options?.merge !== false;
950
- const updateData = {
951
- data: merge ? updates : updates,
1001
+ if (merge) {
1002
+ const updateData = {
1003
+ updatedAt: client.serverTimestamp()
1004
+ };
1005
+ for (const [key, value] of Object.entries(updates)) {
1006
+ updateData[`data.${key}`] = value;
1007
+ }
1008
+ await client.updateDoc(roomRef, updateData);
1009
+ return;
1010
+ }
1011
+ await client.updateDoc(roomRef, {
1012
+ data: updates,
952
1013
  updatedAt: client.serverTimestamp()
953
- };
954
- await client.updateDoc(roomRef, updateData);
1014
+ });
955
1015
  }
956
1016
  // ===== MESSAGE OPERATIONS =====
957
1017
  async sendRoomMessageAsync(room, request) {
@@ -1003,104 +1063,122 @@ var FirestoreRoomsApi = class {
1003
1063
  async subscribeAsync(room, options) {
1004
1064
  const client = await this.getClient();
1005
1065
  const unsubscribers = [];
1006
- if (options?.onData) {
1007
- const roomRef = client.doc(client.firestore, `h5_rooms/${room.id}`);
1008
- const unsubscribeData = client.onSnapshot(
1009
- roomRef,
1010
- (snapshot) => {
1011
- if (snapshot.exists()) {
1012
- const roomData = {
1013
- id: snapshot.id,
1014
- ...snapshot.data()
1015
- };
1016
- const update = {
1017
- type: "H5_ROOM_DATA_UPDATED",
1018
- roomId: room.id,
1019
- roomData,
1020
- timestamp: Date.now()
1021
- };
1022
- options.onData(update);
1023
- }
1024
- },
1025
- (error) => {
1026
- console.error("[Venus SDK] Room subscription error:", error);
1066
+ const cleanupPartialSubscriptions = () => {
1067
+ for (const unsub of unsubscribers) {
1068
+ try {
1069
+ unsub();
1070
+ } catch (e) {
1071
+ console.error("[Venus SDK] Error during room subscription cleanup:", e);
1027
1072
  }
1028
- );
1029
- unsubscribers.push(unsubscribeData);
1030
- }
1031
- if (options?.onMessages) {
1032
- const messagesRef = client.collection(client.firestore, `h5_rooms/${room.id}/messages`);
1033
- const messagesQuery = client.query(
1034
- messagesRef,
1035
- client.orderBy("timestamp", "desc"),
1036
- client.limit(50)
1037
- );
1038
- const unsubscribeMessages = client.onSnapshot(
1039
- messagesQuery,
1040
- (snapshot) => {
1041
- snapshot.docChanges().forEach((change) => {
1042
- const messageData = {
1043
- id: change.doc.id,
1044
- ...change.doc.data()
1045
- };
1046
- let eventType;
1047
- if (change.type === "added") {
1048
- eventType = "H5_ROOM_MESSAGE_RECEIVED";
1049
- } else if (change.type === "modified") {
1050
- eventType = "H5_ROOM_MESSAGE_UPDATED";
1051
- } else {
1052
- eventType = "H5_ROOM_MESSAGE_DELETED";
1073
+ }
1074
+ };
1075
+ try {
1076
+ if (options?.onData) {
1077
+ const roomRef = client.doc(client.firestore, `h5_rooms/${room.id}`);
1078
+ const unsubscribeData = client.onSnapshot(
1079
+ roomRef,
1080
+ (snapshot) => {
1081
+ if (snapshot.exists()) {
1082
+ const roomData = {
1083
+ id: snapshot.id,
1084
+ ...snapshot.data()
1085
+ };
1086
+ const update = {
1087
+ type: "H5_ROOM_DATA_UPDATED",
1088
+ roomId: room.id,
1089
+ roomData,
1090
+ timestamp: Date.now()
1091
+ };
1092
+ options.onData(update);
1053
1093
  }
1054
- const event = {
1055
- type: eventType,
1056
- roomId: room.id,
1057
- message: messageData,
1058
- timestamp: Date.now()
1059
- };
1060
- options.onMessages(event);
1061
- });
1062
- },
1063
- (error) => {
1064
- console.error("[Venus SDK] Messages subscription error:", error);
1065
- }
1066
- );
1067
- unsubscribers.push(unsubscribeMessages);
1068
- }
1069
- if (options?.onGameEvents) {
1070
- const movesRef = client.collection(client.firestore, `h5_rooms/${room.id}/proposed_moves`);
1071
- const movesQuery = client.query(
1072
- movesRef,
1073
- client.orderBy("timestamp", "desc"),
1074
- client.limit(10)
1075
- );
1076
- const unsubscribeMoves = client.onSnapshot(
1077
- movesQuery,
1078
- (snapshot) => {
1079
- snapshot.docChanges().forEach((change) => {
1080
- const moveData = {
1081
- id: change.doc.id,
1082
- ...change.doc.data()
1083
- };
1084
- const event = {
1085
- type: "app:h5:proposedMoveValidationUpdated",
1086
- roomId: room.id,
1087
- proposedMoveData: moveData,
1088
- proposedMoveId: change.doc.id,
1089
- changeType: change.type,
1090
- timestamp: Date.now()
1091
- };
1092
- options.onGameEvents(event);
1093
- });
1094
- },
1095
- (error) => {
1096
- console.error("[Venus SDK] Proposed moves subscription error:", error);
1097
- }
1098
- );
1099
- unsubscribers.push(unsubscribeMoves);
1094
+ },
1095
+ (error) => {
1096
+ console.error("[Venus SDK] Room subscription error:", error);
1097
+ }
1098
+ );
1099
+ unsubscribers.push(unsubscribeData);
1100
+ }
1101
+ if (options?.onMessages) {
1102
+ const messagesRef = client.collection(client.firestore, `h5_rooms/${room.id}/messages`);
1103
+ const messagesQuery = client.query(
1104
+ messagesRef,
1105
+ client.orderBy("timestamp", "desc"),
1106
+ client.limit(50)
1107
+ );
1108
+ const unsubscribeMessages = client.onSnapshot(
1109
+ messagesQuery,
1110
+ (snapshot) => {
1111
+ snapshot.docChanges().forEach((change) => {
1112
+ const messageData = {
1113
+ id: change.doc.id,
1114
+ ...change.doc.data()
1115
+ };
1116
+ let eventType;
1117
+ if (change.type === "added") {
1118
+ eventType = "H5_ROOM_MESSAGE_RECEIVED";
1119
+ } else if (change.type === "modified") {
1120
+ eventType = "H5_ROOM_MESSAGE_UPDATED";
1121
+ } else {
1122
+ eventType = "H5_ROOM_MESSAGE_DELETED";
1123
+ }
1124
+ const event = {
1125
+ type: eventType,
1126
+ roomId: room.id,
1127
+ message: messageData,
1128
+ timestamp: Date.now()
1129
+ };
1130
+ options.onMessages(event);
1131
+ });
1132
+ },
1133
+ (error) => {
1134
+ console.error("[Venus SDK] Messages subscription error:", error);
1135
+ }
1136
+ );
1137
+ unsubscribers.push(unsubscribeMessages);
1138
+ }
1139
+ if (options?.onGameEvents) {
1140
+ const movesRef = client.collection(client.firestore, `h5_rooms/${room.id}/proposed_moves`);
1141
+ const movesQuery = client.query(
1142
+ movesRef,
1143
+ client.orderBy("timestamp", "desc"),
1144
+ client.limit(10)
1145
+ );
1146
+ const unsubscribeMoves = client.onSnapshot(
1147
+ movesQuery,
1148
+ (snapshot) => {
1149
+ snapshot.docChanges().forEach((change) => {
1150
+ const moveData = {
1151
+ id: change.doc.id,
1152
+ ...change.doc.data()
1153
+ };
1154
+ const event = {
1155
+ type: "app:h5:proposedMoveValidationUpdated",
1156
+ roomId: room.id,
1157
+ proposedMoveData: moveData,
1158
+ proposedMoveId: change.doc.id,
1159
+ changeType: change.type,
1160
+ timestamp: Date.now()
1161
+ };
1162
+ options.onGameEvents(event);
1163
+ });
1164
+ },
1165
+ (error) => {
1166
+ console.error("[Venus SDK] Proposed moves subscription error:", error);
1167
+ }
1168
+ );
1169
+ unsubscribers.push(unsubscribeMoves);
1170
+ }
1171
+ } catch (error) {
1172
+ cleanupPartialSubscriptions();
1173
+ throw error;
1100
1174
  }
1101
1175
  const unsubscribe = () => {
1102
1176
  for (const unsub of unsubscribers) {
1103
- unsub();
1177
+ try {
1178
+ unsub();
1179
+ } catch (e) {
1180
+ console.error("[Venus SDK] Error during room subscription cleanup:", e);
1181
+ }
1104
1182
  }
1105
1183
  this.activeSubscriptions.delete(unsubscribe);
1106
1184
  };
@@ -1277,6 +1355,8 @@ var SandboxHost = class {
1277
1355
  clientReady = null;
1278
1356
  authUnsubscribe = null;
1279
1357
  cleanupFunctions = [];
1358
+ authStateChangeId = 0;
1359
+ authStateUid = null;
1280
1360
  constructor(venusApi) {
1281
1361
  this.venusApi = venusApi;
1282
1362
  this._overlay = this.createOverlay();
@@ -1348,6 +1428,10 @@ var SandboxHost = class {
1348
1428
  this.client = client;
1349
1429
  console.log("[Venus SDK] SandboxHost: Firebase client initialized, currentUser:", client.getCurrentUser()?.uid ?? "none");
1350
1430
  this.authUnsubscribe = client.onAuthStateChanged(async (user) => {
1431
+ const changeId = ++this.authStateChangeId;
1432
+ const expectedUid = user?.uid ?? null;
1433
+ this.authStateUid = expectedUid;
1434
+ const isStale = () => this.authStateChangeId !== changeId || this.authStateUid !== expectedUid;
1351
1435
  console.log("[Venus SDK] SandboxHost: Auth state changed, user:", user?.uid ?? "signed out");
1352
1436
  broadcastAuthState(user);
1353
1437
  if (!user) {
@@ -1359,19 +1443,22 @@ var SandboxHost = class {
1359
1443
  username: user.email || user.displayName || user.uid.slice(-8),
1360
1444
  name: user.displayName || void 0,
1361
1445
  avatarUrl: user.photoURL || null,
1362
- isAnonymous: true
1446
+ isAnonymous: false
1363
1447
  };
1448
+ if (isStale()) return;
1364
1449
  await this.ensureProfileExists(user);
1450
+ if (isStale()) return;
1365
1451
  try {
1366
1452
  const backendProfile = await callRemoteFunction("getProfile", {});
1453
+ if (isStale()) return;
1367
1454
  if (backendProfile?.id && backendProfile?.username) {
1368
1455
  this.venusApi._profileData = {
1369
1456
  id: backendProfile.id,
1370
1457
  username: backendProfile.username,
1371
1458
  name: backendProfile.name || void 0,
1372
1459
  avatarUrl: backendProfile.avatarUrl ?? null,
1373
- // Best-effort inference: anonymous profiles are created with empty name in this backend
1374
- isAnonymous: (backendProfile.name ?? "").trim().length === 0
1460
+ // Sandbox users are always authenticated (via OAuth), never anonymous
1461
+ isAnonymous: false
1375
1462
  };
1376
1463
  }
1377
1464
  } catch (error) {
@@ -1458,8 +1545,8 @@ var SandboxHost = class {
1458
1545
  name: user.displayName || `Dev User ${shortId}`,
1459
1546
  username: `dev_${shortId}_${timestamp}`,
1460
1547
  description: "Auto-created for sandbox development",
1461
- isAnonymous: true,
1462
- // Uses retry logic for username conflicts
1548
+ isAnonymous: false,
1549
+ // Sandbox users are authenticated, not anonymous
1463
1550
  onboardingCompleted: true
1464
1551
  });
1465
1552
  console.log("[Venus SDK] Profile created for user:", user.uid);
@@ -1887,8 +1974,8 @@ var SandboxHost = class {
1887
1974
  resolve(null);
1888
1975
  });
1889
1976
  actionSheet.appendChild(closeButton);
1890
- overlay.actionSheetOverlay.appendChild(actionSheet);
1891
1977
  }
1978
+ overlay.actionSheetOverlay.appendChild(actionSheet);
1892
1979
  });
1893
1980
  }
1894
1981
  hideActionSheetOverlay() {
@@ -1938,5 +2025,5 @@ var SandboxHost = class {
1938
2025
  };
1939
2026
 
1940
2027
  export { SandboxHost };
1941
- //# sourceMappingURL=SandboxHost-2Q5PK7LP.js.map
1942
- //# sourceMappingURL=SandboxHost-2Q5PK7LP.js.map
2028
+ //# sourceMappingURL=SandboxHost-O6AJRABC.js.map
2029
+ //# sourceMappingURL=SandboxHost-O6AJRABC.js.map