Files
ss-tools/frontend/src/lib/stores/environmentContext.js

142 lines
3.7 KiB
JavaScript

// [DEF:environmentContext:Store]
// @TIER: STANDARD
// @PURPOSE: Global selected environment context for navigation and safety cues.
// @LAYER: UI-State
import { derived, get, writable } from "svelte/store";
import { browser } from "$app/environment";
import { api } from "$lib/api.js";
const INITIAL_STATE = {
environments: [],
selectedEnvId: "",
isLoading: false,
isLoaded: false,
error: null,
};
const SELECTED_ENV_KEY = "selected_env_id";
const contextStore = writable(INITIAL_STATE);
function getStoredSelectedEnvId() {
if (!browser) return "";
return localStorage.getItem(SELECTED_ENV_KEY) || "";
}
function persistSelectedEnvId(envId) {
if (!browser) return;
if (!envId) {
localStorage.removeItem(SELECTED_ENV_KEY);
return;
}
localStorage.setItem(SELECTED_ENV_KEY, envId);
}
function hasAuthToken() {
if (!browser) return false;
return Boolean(localStorage.getItem("auth_token"));
}
function resolveSelectedEnvId(environments, preferredEnvId) {
if (!Array.isArray(environments) || environments.length === 0) return "";
if (preferredEnvId && environments.some((env) => env.id === preferredEnvId)) {
return preferredEnvId;
}
const stored = getStoredSelectedEnvId();
if (stored && environments.some((env) => env.id === stored)) {
return stored;
}
return environments[0].id;
}
function applySelectedEnvId(selectedEnvId) {
contextStore.update((state) => {
const exists = state.environments.some((env) => env.id === selectedEnvId);
const nextSelectedEnvId = exists ? selectedEnvId : "";
persistSelectedEnvId(nextSelectedEnvId);
return { ...state, selectedEnvId: nextSelectedEnvId };
});
}
async function refreshEnvironmentContext(preferredEnvId = "") {
if (!hasAuthToken()) {
contextStore.update((state) => ({
...state,
isLoading: false,
isLoaded: false,
error: null,
}));
return;
}
contextStore.update((state) => ({ ...state, isLoading: true, error: null }));
try {
const environments = await api.getEnvironmentsList();
const current = get(contextStore).selectedEnvId;
const selectedEnvId = resolveSelectedEnvId(
environments,
preferredEnvId || current,
);
persistSelectedEnvId(selectedEnvId);
contextStore.update((state) => ({
...state,
environments,
selectedEnvId,
isLoading: false,
isLoaded: true,
error: null,
}));
} catch (error) {
if (error?.status === 401) {
contextStore.update((state) => ({
...state,
isLoading: false,
isLoaded: false,
error: null,
}));
return;
}
console.error(
"[environmentContext][Coherence:Failed] Failed to refresh environments",
error,
);
contextStore.update((state) => ({
...state,
environments: [],
selectedEnvId: "",
isLoading: false,
isLoaded: true,
error: error?.message || "Failed to load environments",
}));
}
}
async function initializeEnvironmentContext() {
const state = get(contextStore);
if (state.isLoading || state.isLoaded) return;
await refreshEnvironmentContext();
}
export const environmentContextStore = {
subscribe: contextStore.subscribe,
};
export function setSelectedEnvironment(envId) {
applySelectedEnvId(envId);
}
export { refreshEnvironmentContext, initializeEnvironmentContext };
export const selectedEnvironmentStore = derived(
environmentContextStore,
($context) =>
$context.environments.find((env) => env.id === $context.selectedEnvId) ||
null,
);
export const isProductionContextStore = derived(
selectedEnvironmentStore,
($selectedEnvironment) => Boolean($selectedEnvironment?.is_production),
);
// [/DEF:environmentContext:Store]