@series-inc/venus-sdk 5.0.1 → 5.0.2

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.
@@ -1,4 +1,4 @@
1
- /* raw-loader:/Users/pchan/Development/series/venus/venus-sdk/packages/api/src/vite/sandboxToolbarStyle.css */
1
+ /* raw-loader:E:\SeriesAI\venus\venus-sdk\packages\api\src\vite\sandboxToolbarStyle.css */
2
2
  input[style*="background: rgba(0, 0, 0, 0.2)"],
3
3
  select[style*="background: rgba(0, 0, 0, 0.2)"] {
4
4
  box-sizing: border-box;
@@ -1 +1 @@
1
- {"version":3,"sources":["raw-loader:/Users/pchan/Development/series/venus/venus-sdk/packages/api/src/vite/sandboxToolbarStyle.css"],"sourcesContent":["/* Minimal CSS - FAB uses inline styles only for guaranteed floating behavior */\r\n\r\n/* Optional: Override input styling for modal if needed */\r\ninput[style*=\"background: rgba(0, 0, 0, 0.2)\"],\r\nselect[style*=\"background: rgba(0, 0, 0, 0.2)\"] {\r\n box-sizing: border-box;\r\n}\r\n\r\ninput[style*=\"background: rgba(0, 0, 0, 0.2)\"]:focus,\r\nselect[style*=\"background: rgba(0, 0, 0, 0.2)\"]:focus {\r\n outline: none;\r\n border-color: rgba(59, 130, 246, 0.5) !important;\r\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\r\n}\r\n\r\nbutton[style*=\"background: #3B82F6\"]:hover {\r\n background: #2563EB !important;\r\n}\r\n\r\nbutton[style*=\"background: #3B82F6\"]:disabled {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n}\r\n"],"mappings":";AAGA,KAAK,CAAC;AACN,MAAM,CAAC;AACL,cAAY;AACd;AAEA,KAAK,CAAC,wCAAwC;AAC9C,MAAM,CAAC,wCAAwC;AAC7C,WAAS;AACT,gBAAc,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE;AACjC,cAAY,EAAE,EAAE,EAAE,IAAI,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE;AAC3C;AAEA,MAAM,CAAC,6BAA6B;AAClC,cAAY;AACd;AAEA,MAAM,CAAC,6BAA6B;AAClC,WAAS;AACT,UAAQ;AACV;","names":[]}
1
+ {"version":3,"sources":["raw-loader:E:\\SeriesAI\\venus\\venus-sdk\\packages\\api\\src\\vite\\sandboxToolbarStyle.css"],"sourcesContent":["/* Minimal CSS - FAB uses inline styles only for guaranteed floating behavior */\r\n\r\n/* Optional: Override input styling for modal if needed */\r\ninput[style*=\"background: rgba(0, 0, 0, 0.2)\"],\r\nselect[style*=\"background: rgba(0, 0, 0, 0.2)\"] {\r\n box-sizing: border-box;\r\n}\r\n\r\ninput[style*=\"background: rgba(0, 0, 0, 0.2)\"]:focus,\r\nselect[style*=\"background: rgba(0, 0, 0, 0.2)\"]:focus {\r\n outline: none;\r\n border-color: rgba(59, 130, 246, 0.5) !important;\r\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\r\n}\r\n\r\nbutton[style*=\"background: #3B82F6\"]:hover {\r\n background: #2563EB !important;\r\n}\r\n\r\nbutton[style*=\"background: #3B82F6\"]:disabled {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n}\r\n"],"mappings":";AAGA,KAAK,CAAC;AACN,MAAM,CAAC;AACL,cAAY;AACd;AAEA,KAAK,CAAC,wCAAwC;AAC9C,MAAM,CAAC,wCAAwC;AAC7C,WAAS;AACT,gBAAc,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE;AACjC,cAAY,EAAE,EAAE,EAAE,IAAI,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE;AAC3C;AAEA,MAAM,CAAC,6BAA6B;AAClC,cAAY;AACd;AAEA,MAAM,CAAC,6BAA6B;AAClC,WAAS;AACT,UAAQ;AACV;","names":[]}
@@ -1133,10 +1133,10 @@ function cdnPlugin() {
1133
1133
  };
1134
1134
  }
1135
1135
 
1136
- // raw-loader:/Users/pchan/Development/series/venus/venus-sdk/packages/api/src/vite/sandboxToolbarStyle.css
1136
+ // raw-loader:E:\SeriesAI\venus\venus-sdk\packages\api\src\vite\sandboxToolbarStyle.css
1137
1137
  var sandboxToolbarStyle_default = {};
1138
1138
 
1139
- // compiled-string-loader:/Users/pchan/Development/series/venus/venus-sdk/packages/api/src/vite/sandboxToolbarScript.ts
1139
+ // compiled-string-loader:E:\SeriesAI\venus\venus-sdk\packages\api\src\vite\sandboxToolbarScript.ts
1140
1140
  var sandboxToolbarScript_default = 'const LOCAL_STORAGE_POS_KEY = "venus-sandbox-pos";\nconst LOCAL_STORAGE_PLAYER_KEY = "venus-sandbox-selected-player";\nconst LOCAL_STORAGE_MAX_PLAYER_KEY = "venus-sandbox-max-player";\nlet inMemorySelectedPlayerId = "player1";\nfunction getMaxPlayerNumber() {\n const selected = getSelectedPlayerId();\n const selectedMatch = String(selected).match(/^player(\\d+)$/);\n const selectedN = selectedMatch ? parseInt(selectedMatch[1], 10) : 1;\n try {\n const raw = localStorage.getItem(LOCAL_STORAGE_MAX_PLAYER_KEY);\n const n = parseInt(String(raw || "").trim(), 10);\n const safe = Number.isFinite(n) && n >= 1 ? n : 1;\n return Math.max(safe, Number.isFinite(selectedN) ? selectedN : 1);\n } catch {\n return Math.max(1, Number.isFinite(selectedN) ? selectedN : 1);\n }\n}\nfunction setMaxPlayerNumber(n) {\n const safe = Number.isFinite(n) && n >= 1 ? Math.floor(n) : 1;\n try {\n localStorage.setItem(LOCAL_STORAGE_MAX_PLAYER_KEY, String(safe));\n } catch {\n }\n return safe;\n}\nfunction getSelectedPlayerId() {\n try {\n const raw = localStorage.getItem(LOCAL_STORAGE_PLAYER_KEY);\n const candidate = (raw || "").trim().toLowerCase();\n if (!candidate) return "player1";\n if (!/^player\\d+$/.test(candidate)) return "player1";\n const n = parseInt(candidate.replace("player", ""), 10);\n if (!Number.isFinite(n) || n < 1) return "player1";\n const normalized = `player${n}`;\n inMemorySelectedPlayerId = normalized;\n return normalized;\n } catch {\n return inMemorySelectedPlayerId || "player1";\n }\n}\nfunction setSelectedPlayerId(playerId) {\n const normalized = String(playerId || "").trim().toLowerCase();\n const safe = /^player\\d+$/.test(normalized) ? normalized : "player1";\n inMemorySelectedPlayerId = safe;\n try {\n localStorage.setItem(LOCAL_STORAGE_PLAYER_KEY, safe);\n } catch {\n }\n return safe;\n}\nfunction nextPlayerId(currentPlayerId) {\n const current = String(currentPlayerId || "").trim().toLowerCase();\n const match = current.match(/^player(\\d+)$/);\n const n = match ? parseInt(match[1], 10) : 1;\n const next = Number.isFinite(n) && n >= 1 ? n + 1 : 2;\n return `player${next}`;\n}\nfunction buildPlayerSelectOptions(selectedPlayerId, maxPlayerNumber) {\n const selected = String(selectedPlayerId || "player1").trim().toLowerCase();\n const maxN = Number.isFinite(maxPlayerNumber) && maxPlayerNumber >= 1 ? maxPlayerNumber : 1;\n let html = "";\n for (let i = 1; i <= maxN; i++) {\n const value = `player${i}`;\n const selectedAttr = value === selected ? " selected" : "";\n html += `<option value="${value}"${selectedAttr}>${value}</option>`;\n }\n html += `<option value="__new__">+ New player\\u2026</option>`;\n return html;\n}\n;\n(async () => {\n try {\n if (!shouldRenderToolbar()) {\n return;\n }\n await ensureDomReady();\n const sandboxConfig = window.__VENUS_SANDBOX__ || {};\n const sandboxEnabled = isSandboxEnabled(sandboxConfig);\n if (!sandboxEnabled) {\n return;\n }\n createFloatingToolbar(sandboxConfig);\n } catch (error) {\n console.error("[Venus Sandbox] Failed to render toolbar:", error);\n }\n})();\nfunction shouldRenderToolbar() {\n if (typeof window === "undefined") {\n return false;\n }\n const host = location.hostname;\n return host === "localhost" || host === "127.0.0.1" || host.endsWith(".local");\n}\nfunction ensureDomReady() {\n if (document.readyState === "loading") {\n return new Promise((resolve) => {\n document.addEventListener("DOMContentLoaded", resolve, { once: true });\n });\n }\n return Promise.resolve();\n}\nfunction isSandboxEnabled(sandboxConfig) {\n return Boolean(sandboxConfig && sandboxConfig.enabled === true);\n}\nfunction createFloatingToolbar(sandboxConfig) {\n const fab = document.createElement("div");\n fab.id = "venus-sandbox-toolbar";\n const target = String(sandboxConfig?.target || "local").toLowerCase();\n const envGradients = {\n local: "linear-gradient(120deg, #f59e0b, #d97706)",\n dev: "linear-gradient(120deg, #0891b2, #10b981)",\n staging: "linear-gradient(120deg, #8b5cf6, #6366f1)"\n };\n const envLabels = {\n local: "LOCAL",\n dev: "DEV",\n staging: "STAGING"\n };\n const initialGradient = envGradients[target] || envGradients.local;\n const envLabel = envLabels[target] || "LOCAL";\n const savedPos = localStorage.getItem(LOCAL_STORAGE_POS_KEY);\n let posRight = 16;\n let posY = Math.round((window.innerHeight - 36) / 2);\n if (savedPos) {\n try {\n const parsed = JSON.parse(savedPos);\n posRight = parsed.right;\n posY = parsed.y;\n } catch (e) {\n }\n }\n posRight = Math.min(Math.max(0, posRight), window.innerWidth - 36);\n posY = Math.min(Math.max(0, posY), window.innerHeight - 36);\n fab.style.cssText = `\n position: fixed;\n right: ${posRight}px;\n top: ${posY}px;\n width: auto;\n min-width: 160px;\n height: 36px;\n padding: 0;\n margin: 0;\n border: none;\n border-radius: 999px;\n background: ${initialGradient};\n color: #ffffff;\n font-family: system-ui, -apple-system, sans-serif;\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.02em;\n cursor: grab;\n user-select: none;\n z-index: 2147483601;\n box-shadow: 0 12px 25px rgba(0, 0, 0, 0.35);\n display: flex;\n align-items: center;\n gap: 0;\n pointer-events: auto;\n border: 1px solid rgba(255, 255, 255, 0.2);\n `;\n fab.dataset.target = target;\n fab.dataset.envGradient = initialGradient;\n const envBadge = document.createElement("div");\n envBadge.style.cssText = `\n padding: 0 10px;\n height: 100%;\n display: flex;\n align-items: center;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n background: rgba(0, 0, 0, 0.2);\n border-top-left-radius: 999px;\n border-bottom-left-radius: 999px;\n `;\n envBadge.textContent = envLabel;\n const labelDiv = document.createElement("div");\n labelDiv.style.cssText = `\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 12px;\n height: 100%;\n font-size: 12px;\n font-weight: 600;\n background: rgba(0, 0, 0, 0.1);\n cursor: pointer;\n `;\n labelDiv.textContent = "\\u25CB Sign in";\n const handleDiv = document.createElement("div");\n handleDiv.style.cssText = `\n width: 36px;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n font-weight: 600;\n background: rgba(0, 0, 0, 0.25);\n border-top-right-radius: 999px;\n border-bottom-right-radius: 999px;\n cursor: grab;\n `;\n handleDiv.textContent = "\\u271C";\n fab.appendChild(envBadge);\n fab.appendChild(labelDiv);\n fab.appendChild(handleDiv);\n const toolbarRoot = document.getElementById("venus-toolbar-root");\n (toolbarRoot || document.body).appendChild(fab);\n setupDragHandling(fab, handleDiv);\n setupCollapseExpand(fab, envBadge, labelDiv);\n labelDiv.addEventListener("click", () => {\n openAuthModal(sandboxConfig, getCurrentAuthState());\n });\n window.addEventListener("venus-auth-state-changed", (e) => {\n updateToolbarState(fab, labelDiv, e.detail);\n });\n setTimeout(() => {\n checkInitialAuthState(fab, labelDiv, sandboxConfig);\n }, 500);\n}\nlet currentAuthState = { signedIn: false, user: null };\nfunction getCurrentAuthState() {\n return currentAuthState;\n}\nfunction checkInitialAuthState(fab, labelDiv, sandboxConfig) {\n window.dispatchEvent(new CustomEvent("venus-check-auth-state"));\n setTimeout(() => {\n if (!currentAuthState.signedIn) {\n updateToolbarState(fab, labelDiv, { signedIn: false, user: null });\n }\n }, 2e3);\n}\nfunction updateToolbarState(fab, labelDiv, authState) {\n currentAuthState = authState;\n const envGradient = fab.dataset.envGradient || "linear-gradient(120deg, #f59e0b, #d97706)";\n const isLocal = String(fab.dataset.target || "").toLowerCase() === "local";\n if (authState.signedIn && authState.user) {\n fab.style.background = envGradient;\n fab.style.opacity = "1";\n const displayName = authState.user.displayName || authState.user.email || "Signed in";\n labelDiv.textContent = `\\u2713 ${truncate(displayName, 14)}`;\n } else {\n fab.style.background = envGradient;\n fab.style.opacity = "0.85";\n labelDiv.textContent = isLocal ? `\\u25CB ${getSelectedPlayerId()}` : "\\u25CB Sign in";\n }\n}\nfunction truncate(str, maxLength) {\n if (str.length <= maxLength) return str;\n return str.substring(0, maxLength - 1) + "\\u2026";\n}\nfunction setupCollapseExpand(fab, envBadge, labelDiv) {\n let collapseTimeout;\n let isCollapsed = false;\n const collapse = () => {\n fab.style.minWidth = "36px";\n fab.style.opacity = "0.4";\n envBadge.style.display = "none";\n labelDiv.style.display = "none";\n isCollapsed = true;\n };\n const expand = () => {\n clearTimeout(collapseTimeout);\n fab.style.minWidth = "160px";\n fab.style.opacity = "1";\n envBadge.style.display = "flex";\n labelDiv.style.display = "flex";\n isCollapsed = false;\n };\n const scheduleCollapse = () => {\n clearTimeout(collapseTimeout);\n collapseTimeout = setTimeout(collapse, 5e3);\n };\n scheduleCollapse();\n fab.addEventListener("mouseenter", expand);\n fab.addEventListener("mouseleave", () => {\n if (!isCollapsed) scheduleCollapse();\n });\n}\nfunction setupDragHandling(fab, handleDiv) {\n let isDragging = false;\n let startX, startY, offsetRight, offsetY;\n fab.addEventListener("mousedown", (e) => {\n isDragging = true;\n startX = e.clientX;\n startY = e.clientY;\n offsetRight = window.innerWidth - fab.offsetLeft - fab.offsetWidth;\n offsetY = fab.offsetTop;\n fab.style.cursor = "grabbing";\n e.preventDefault();\n });\n document.addEventListener("mousemove", (e) => {\n if (!isDragging) return;\n let newRight = offsetRight - (e.clientX - startX);\n let newTop = offsetY + (e.clientY - startY);\n newRight = Math.min(Math.max(0, newRight), window.innerWidth - 36);\n newTop = Math.min(Math.max(0, newTop), window.innerHeight - 36);\n fab.style.right = `${newRight}px`;\n fab.style.top = `${newTop}px`;\n });\n document.addEventListener("mouseup", () => {\n if (!isDragging) return;\n isDragging = false;\n fab.style.cursor = "grab";\n const currentRight = window.innerWidth - fab.offsetLeft - fab.offsetWidth;\n localStorage.setItem(\n LOCAL_STORAGE_POS_KEY,\n JSON.stringify({\n right: currentRight,\n y: fab.offsetTop\n })\n );\n });\n}\nfunction openAuthModal(sandboxConfig, authState) {\n const overlay = document.createElement("div");\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.6);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 2147483602;\n backdrop-filter: blur(4px);\n `;\n const content = document.createElement("div");\n content.style.cssText = `\n background: #111827;\n color: #F3F4F6;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n width: 90%;\n max-width: 420px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.6);\n font-family: system-ui, -apple-system, sans-serif;\n overflow: hidden;\n `;\n const target = String(sandboxConfig?.target || "local").toLowerCase();\n const targetUpper = target.toUpperCase();\n const gameId = sandboxConfig?.gameId || "Unknown";\n const isSignedIn = authState.signedIn;\n const user = authState.user;\n const isLocal = target === "local";\n const selectedPlayerId = isLocal ? getSelectedPlayerId() : null;\n const maxPlayerNumber = isLocal ? getMaxPlayerNumber() : 1;\n if (isLocal) {\n setMaxPlayerNumber(maxPlayerNumber);\n }\n const envConfig = {\n local: {\n gradient: "linear-gradient(120deg, #f59e0b, #d97706)",\n badge: "#f59e0b",\n badgeBg: "rgba(245, 158, 11, 0.15)",\n label: "LOCAL",\n subtitle: "Firebase Emulator"\n },\n dev: {\n gradient: "linear-gradient(120deg, #0891b2, #10b981)",\n badge: "#10b981",\n badgeBg: "rgba(16, 185, 129, 0.15)",\n label: "DEV",\n subtitle: "Development Server"\n },\n staging: {\n gradient: "linear-gradient(120deg, #8b5cf6, #6366f1)",\n badge: "#8b5cf6",\n badgeBg: "rgba(139, 92, 246, 0.15)",\n label: "STAGING",\n subtitle: "Staging Server"\n }\n };\n const env = envConfig[target] || envConfig.local;\n const statusIcon = isSignedIn ? "\\u2713" : "\\u25CB";\n const statusText = isSignedIn ? "Signed in" : "Not signed in";\n const statusColor = isSignedIn ? "#10b981" : "#6b7280";\n const userDisplay = user ? user.displayName || user.email || "Unknown" : "\\u2014";\n const userIdShort = user?.uid ? user.uid.slice(0, 8) + "..." : "";\n content.innerHTML = `\n <div style="\n background: ${env.gradient};\n padding: 20px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n ">\n <div style="display: flex; align-items: center; gap: 10px;">\n <span style="font-size: 24px;">\\u{1FA90}</span>\n <div>\n <div style="font-size: 16px; font-weight: 700;">Venus Sandbox</div>\n <div style="font-size: 12px; opacity: 0.9;">${env.subtitle}</div>\n </div>\n </div>\n <button id="close-modal" style="\n background: rgba(0, 0, 0, 0.15);\n border: none;\n color: white;\n width: 32px;\n height: 32px;\n border-radius: 999px;\n cursor: pointer;\n font-size: 18px;\n ">\\xD7</button>\n </div>\n\n <div style="padding: 24px;">\n <div style="display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px;">\n <span style="\n padding: 4px 10px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 700;\n background: ${env.badgeBg};\n color: ${env.badge};\n ">${targetUpper}</span>\n <span style="\n padding: 4px 10px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 700;\n background: rgba(255, 255, 255, 0.08);\n color: rgba(255, 255, 255, 0.85);\n ">gameId: ${gameId}</span>\n </div>\n\n <div style="\n padding: 14px 16px;\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 10px;\n margin-bottom: 14px;\n ">\n <div style="display:flex; align-items:center; justify-content:space-between; gap: 10px; flex-wrap: wrap;">\n <div style="display:flex; align-items:center; gap: 10px; flex: 1; min-width: 0;">\n <div style="\n width: 30px;\n height: 30px;\n border-radius: 999px;\n display:flex;\n align-items:center;\n justify-content:center;\n background: rgba(255,255,255,0.06);\n border: 1px solid rgba(255,255,255,0.08);\n font-weight: 800;\n color: ${statusColor};\n ">${statusIcon}</div>\n <div style="min-width: 0;">\n ${// Local emulator UX: when signed out, show the player dropdown right where the status goes.\n // When signed in, show the normal status + user display.\n !isSignedIn && isLocal ? `\n <div style="font-size: 11px; font-weight: 700; color: rgba(255,255,255,0.75); letter-spacing: 0.05em; text-transform: uppercase;">Local Player</div>\n <select id="local-player-select" style="\n margin-top: 6px;\n width: 180px;\n max-width: 45vw;\n min-width: 130px;\n background: rgba(0, 0, 0, 0.25);\n color: #F3F4F6;\n border: 1px solid rgba(255, 255, 255, 0.10);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 13px;\n font-weight: 800;\n outline: none;\n appearance: auto;\n ">\n ${buildPlayerSelectOptions(selectedPlayerId, maxPlayerNumber)}\n </select>\n ` : `\n <div style="font-size: 13px; font-weight: 700;">${statusText}</div>\n <div style="font-size: 11px; color: rgba(255,255,255,0.6); margin-top: 2px;">\n ${isSignedIn ? `${userDisplay} ${userIdShort ? `(${userIdShort})` : ""}` : "Click sign in to authenticate"}\n </div>\n `}\n </div>\n </div>\n <div>\n ${isSignedIn ? `\n <button id="sign-out" style="\n background: rgba(239, 68, 68, 0.12);\n color: #fecaca;\n border: 1px solid rgba(239, 68, 68, 0.25);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n ">Sign out</button>\n ` : `\n <button id="sign-in-google" style="\n background: rgba(255, 255, 255, 0.12);\n color: #ffffff;\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n ">Sign in</button>\n `}\n </div>\n </div>\n </div>\n\n <div style="\n padding: 12px 14px;\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 10px;\n margin-bottom: 14px;\n font-size: 12px;\n color: rgba(255, 255, 255, 0.75);\n line-height: 1.5;\n ">\n <div style="font-weight: 600; margin-bottom: 4px; color: #c7d2fe;">\\u{1F4A1} Change environment:</div>\n <code style="\n display: block;\n background: rgba(0, 0, 0, 0.3);\n padding: 8px 10px;\n border-radius: 5px;\n font-family: \'SF Mono\', Monaco, monospace;\n font-size: 11px;\n color: #e0e7ff;\n margin-top: 6px;\n ">venus set-env &lt;local|dev|staging&gt;</code>\n </div>\n\n ${isLocal ? `\n <div style="\n padding: 10px 14px;\n background: rgba(245, 158, 11, 0.08);\n border: 1px solid rgba(245, 158, 11, 0.15);\n border-radius: 8px;\n font-size: 11px;\n color: #fcd34d;\n line-height: 1.5;\n margin-bottom: 14px;\n ">\n <strong>Emulator mode:</strong> Profiles are auto-created on first sign-in.\n <a href="http://localhost:4000" target="_blank" style="color: #fbbf24; text-decoration: underline; margin-left: 4px;">Open Emulator UI \\u2192</a>\n </div>\n ` : ""}\n\n <!-- Local player selection is shown in the auth card (signed-out local mode) -->\n\n <div style="display:flex; gap: 10px;">\n <button id="reload-page" style="\n flex: 1;\n background: rgba(255, 255, 255, 0.06);\n color: rgba(255, 255, 255, 0.85);\n border: 1px solid rgba(255, 255, 255, 0.10);\n border-radius: 10px;\n padding: 10px 12px;\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n ">Reload page</button>\n </div>\n </div>\n `;\n overlay.appendChild(content);\n document.body.appendChild(overlay);\n const $ = (selector) => content.querySelector(selector);\n const closeModal = () => overlay.remove();\n const closeBtn = $("#close-modal");\n if (closeBtn) closeBtn.addEventListener("click", closeModal);\n overlay.addEventListener("click", (e) => {\n if (e.target === overlay) closeModal();\n });\n $("#reload-page")?.addEventListener("click", () => {\n window.location.reload();\n });\n const playerSelect = $("#local-player-select");\n if (playerSelect) {\n playerSelect.addEventListener("change", () => {\n const value = String(playerSelect.value || "").trim().toLowerCase();\n if (value === "__new__") {\n const nextId = nextPlayerId(getSelectedPlayerId());\n const match = String(nextId).match(/^player(\\d+)$/);\n const n = match ? parseInt(match[1], 10) : getMaxPlayerNumber() + 1;\n setMaxPlayerNumber(n);\n const saved = setSelectedPlayerId(`player${n}`);\n playerSelect.innerHTML = buildPlayerSelectOptions(saved, getMaxPlayerNumber());\n playerSelect.value = saved;\n } else {\n setSelectedPlayerId(value);\n }\n const toolbar = document.getElementById("venus-sandbox-toolbar");\n const toolbarLabelDiv = toolbar?.children?.[1];\n const isLocalTarget = (toolbar?.dataset?.target || "").toLowerCase() === "local";\n if (toolbarLabelDiv && isLocalTarget && !currentAuthState.signedIn) {\n toolbarLabelDiv.textContent = `\\u25CB ${getSelectedPlayerId()}`;\n }\n });\n }\n const signInBtn = $("#sign-in-google");\n if (signInBtn) {\n const originalGradient = env.gradient;\n signInBtn.addEventListener("click", async () => {\n try {\n signInBtn.textContent = "Signing in...";\n signInBtn.disabled = true;\n const waitForSignedIn = (timeoutMs) => {\n return new Promise((resolve) => {\n let done = false;\n const cleanup = () => {\n if (done) return;\n done = true;\n window.removeEventListener("venus-auth-state-changed", handler);\n clearTimeout(timer);\n };\n const handler = (e) => {\n if (e?.detail?.signedIn === true) {\n cleanup();\n resolve(true);\n }\n };\n const timer = setTimeout(() => {\n cleanup();\n resolve(false);\n }, timeoutMs);\n if (currentAuthState?.signedIn === true) {\n cleanup();\n resolve(true);\n return;\n }\n window.addEventListener("venus-auth-state-changed", handler);\n });\n };\n const signedInWait = waitForSignedIn(8e3);\n let signInError = null;\n if (isLocal && window.__VENUS_SANDBOX_SIGN_IN_AS__) {\n try {\n const p = window.__VENUS_SANDBOX_SIGN_IN_AS__(getSelectedPlayerId());\n p?.catch?.((err) => {\n signInError = err;\n });\n } catch (err) {\n signInError = err;\n }\n } else if (window.__VENUS_SANDBOX_SIGN_IN__) {\n try {\n const p = window.__VENUS_SANDBOX_SIGN_IN__();\n p?.catch?.((err) => {\n signInError = err;\n });\n } catch (err) {\n signInError = err;\n }\n } else {\n throw new Error("[Venus Sandbox] Sign-in is not available (missing global hook).");\n }\n const signedIn = await signedInWait;\n if (!signedIn) {\n if (signInError) throw signInError;\n throw new Error("[Venus Sandbox] Sign-in timed out. Try reloading and signing in again.");\n }\n signInBtn.textContent = "\\u2713 Success!";\n signInBtn.style.background = "linear-gradient(120deg, #10b981, #059669)";\n setTimeout(() => {\n closeModal();\n window.location.reload();\n }, 700);\n } catch (error) {\n console.error("[Venus Sandbox] Sign-in failed:", error);\n signInBtn.textContent = "Sign in";\n signInBtn.disabled = false;\n signInBtn.style.background = originalGradient;\n alert("Sign-in failed. Check console for details.");\n }\n });\n }\n const signOutBtn = $("#sign-out");\n if (signOutBtn) {\n signOutBtn.addEventListener("click", async () => {\n try {\n signOutBtn.textContent = "Signing out...";\n signOutBtn.disabled = true;\n if (window.__VENUS_SANDBOX_SIGN_OUT__) {\n await window.__VENUS_SANDBOX_SIGN_OUT__();\n }\n closeModal();\n window.location.reload();\n } catch (error) {\n console.error("[Venus Sandbox] Sign-out failed:", error);\n signOutBtn.textContent = "Sign out";\n signOutBtn.disabled = false;\n alert("Sign-out failed. Check console for details.");\n }\n });\n }\n}\n';
1141
1141
 
1142
1142
  // src/vite/sandboxToolbar.ts
@@ -1246,7 +1246,8 @@ function venusSandboxPlugin(options = {}) {
1246
1246
  ...config,
1247
1247
  define: {
1248
1248
  ...config?.define,
1249
- "import.meta.env.VITE_APP_MODE": JSON.stringify("live")
1249
+ "import.meta.env.VITE_APP_MODE": JSON.stringify("live"),
1250
+ __USE_SANDBOX__: "true"
1250
1251
  },
1251
1252
  optimizeDeps: {
1252
1253
  ...config?.optimizeDeps,