import { defineStore } from "pinia"; import { computed, ref } from "vue"; import { loadRuntimeConfig } from "@/utils/runtimeConfig"; interface RuntimeSettings { gatewayUrl: string; gatewayToken: string; } const STORAGE_KEY = "remoteconn:web:settings:v1"; function resolveDefaultGatewayUrl(): string { const env = (import.meta as ImportMeta & { env?: Record }).env; const envUrl = env?.VITE_GATEWAY_URL?.trim(); if (envUrl) return envUrl; if (typeof window === "undefined") return "ws://127.0.0.1:8787/ws/terminal"; const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; return `${protocol}//${window.location.host}/ws/terminal`; } function resolveDefaultGatewayToken(): string { const env = (import.meta as ImportMeta & { env?: Record }).env; const envToken = env?.VITE_GATEWAY_TOKEN?.trim(); if (envToken) return envToken; return "remoteconn-dev-token"; } function loadSettings(): RuntimeSettings { if (typeof window === "undefined") { return { gatewayUrl: resolveDefaultGatewayUrl(), gatewayToken: resolveDefaultGatewayToken() }; } try { const raw = window.localStorage.getItem(STORAGE_KEY); if (!raw) { return { gatewayUrl: resolveDefaultGatewayUrl(), gatewayToken: resolveDefaultGatewayToken() }; } const parsed = JSON.parse(raw) as Partial; return { gatewayUrl: String(parsed.gatewayUrl ?? resolveDefaultGatewayUrl()), gatewayToken: String(parsed.gatewayToken ?? resolveDefaultGatewayToken()) }; } catch { return { gatewayUrl: resolveDefaultGatewayUrl(), gatewayToken: resolveDefaultGatewayToken() }; } } function persistSettings(settings: RuntimeSettings): void { if (typeof window === "undefined") return; try { window.localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); } catch { // ignore storage unavailability in embedded/private contexts } } export const useSettingsStore = defineStore("settings", () => { const settings = ref({ gatewayUrl: resolveDefaultGatewayUrl(), gatewayToken: resolveDefaultGatewayToken() }); const loaded = ref(false); let bootstrapPromise: Promise | null = null; async function ensureBootstrapped(): Promise { if (loaded.value) return; if (bootstrapPromise) { await bootstrapPromise; return; } bootstrapPromise = (async () => { const runtimeConfig = await loadRuntimeConfig(); const localSettings = loadSettings(); settings.value = { gatewayUrl: String(runtimeConfig?.gatewayUrl ?? localSettings.gatewayUrl ?? resolveDefaultGatewayUrl()), gatewayToken: String(runtimeConfig?.gatewayToken ?? localSettings.gatewayToken ?? resolveDefaultGatewayToken()) }; loaded.value = true; })(); try { await bootstrapPromise; } finally { bootstrapPromise = null; } } async function bootstrap(): Promise { await ensureBootstrapped(); } async function save(next: Partial): Promise { settings.value = { gatewayUrl: String(next.gatewayUrl ?? settings.value.gatewayUrl ?? resolveDefaultGatewayUrl()), gatewayToken: String(next.gatewayToken ?? settings.value.gatewayToken ?? resolveDefaultGatewayToken()) }; persistSettings(settings.value); } const gatewayUrl = computed(() => settings.value.gatewayUrl || resolveDefaultGatewayUrl()); const gatewayToken = computed(() => settings.value.gatewayToken || resolveDefaultGatewayToken()); return { settings, gatewayUrl, gatewayToken, ensureBootstrapped, bootstrap, save }; });