111 lines
3.6 KiB
TypeScript
111 lines
3.6 KiB
TypeScript
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<string, string | undefined> }).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<string, string | undefined> }).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<RuntimeSettings>;
|
|
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<RuntimeSettings>({
|
|
gatewayUrl: resolveDefaultGatewayUrl(),
|
|
gatewayToken: resolveDefaultGatewayToken()
|
|
});
|
|
const loaded = ref(false);
|
|
let bootstrapPromise: Promise<void> | null = null;
|
|
|
|
async function ensureBootstrapped(): Promise<void> {
|
|
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<void> {
|
|
await ensureBootstrapped();
|
|
}
|
|
|
|
async function save(next: Partial<RuntimeSettings>): Promise<void> {
|
|
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
|
|
};
|
|
});
|