/** * Dependency-injection provider for the UI ports. * * Chooses one of three transport implementations (ticket #13): the mock adapters * (`VITE_USE_MOCK`), the web HTTP+WS adapters (`VITE_TRANSPORT="http"`), or the * default Tauri desktop adapters. Components consume gateways via * {@link useGateways} and never construct adapters or call `invoke()` themselves. */ import { createContext, useContext, useMemo, type ReactNode, } from "react"; import type { Gateways } from "@/ports"; import { createTauriGateways } from "@/adapters"; import { createMockGateways } from "@/adapters/mock"; import { createHttpWsGateways } from "@/adapters/http"; import { transportFromEnv, type Transport } from "./transport"; const GatewaysContext = createContext(null); export type { Transport }; /** Whether the mock adapters should be used (env-driven, overridable in tests). */ export function shouldUseMock(): boolean { const flag = import.meta.env.VITE_USE_MOCK; return flag === "1" || flag === "true"; } /** * Whether the web (client/server) HTTP+WS adapters should be used. Selected * explicitly via `VITE_TRANSPORT="http"` so the desktop path stays the default * and is never affected (ticket #13, lot F1). */ export function shouldUseHttp(): boolean { return transportFromEnv(import.meta.env.VITE_TRANSPORT) === "http"; } /** Resolves which transport to use. Mock wins, then explicit web, else Tauri. */ export function resolveTransport(): Transport { if (shouldUseMock()) return "mock"; return transportFromEnv(import.meta.env.VITE_TRANSPORT); } /** Resolves the gateway set for the current environment. */ export function resolveGateways(): Gateways { switch (resolveTransport()) { case "mock": return createMockGateways(); case "http": return createHttpWsGateways(); case "tauri": return createTauriGateways(); } } interface DIProviderProps { children: ReactNode; /** Optional explicit gateways (used by tests/Storybook). */ gateways?: Gateways; } export function DIProvider({ children, gateways }: DIProviderProps) { const value = useMemo(() => gateways ?? resolveGateways(), [gateways]); return ( {children} ); } /** Hook returning the injected gateways. Throws if used outside the provider. */ export function useGateways(): Gateways { const ctx = useContext(GatewaysContext); if (!ctx) { throw new Error("useGateways must be used within a "); } return ctx; }