142 lines
3.7 KiB
JavaScript
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]
|