import { createGrpcWebTransport } from "@connectrpc/connect-web"; import { createClient, type Interceptor } from "@connectrpc/connect"; import { getToken, isTokenExpired, clearTokens, SESSION_EXPIRED_KEY, } from "./auth"; // Generated service definitions (protoc-gen-es v2 — services live in *_pb.ts) import { TradingService } from "../gen/trading_pb"; import { RiskService } from "../gen/risk_pb"; import { MLService } from "../gen/ml_pb"; import { MLTrainingService } from "../gen/ml_training_pb"; import { ConfigService } from "../gen/config_pb"; import { MonitoringService } from "../gen/monitoring_pb"; import { BacktestingService } from "../gen/fxt_trading_pb"; import { AuthService } from "../gen/auth_pb"; const API_URL = import.meta.env.VITE_API_URL ?? "http://localhost:50051"; /** Margin in seconds before actual expiry to treat the token as expired */ const EXPIRY_MARGIN_SECONDS = 60; /** * Interceptor that attaches the JWT Authorization header to every request * and handles session expiry / UNAUTHENTICATED responses. */ const authInterceptor: Interceptor = (next) => async (req) => { const token = getToken(); if (token) { if (isTokenExpired(token, EXPIRY_MARGIN_SECONDS)) { sessionStorage.setItem(SESSION_EXPIRED_KEY, "1"); clearTokens(); window.location.href = "/login"; throw new Error("Session expired"); } req.header.set("authorization", `Bearer ${token}`); } try { return await next(req); } catch (err: unknown) { // gRPC status 16 = UNAUTHENTICATED if ( err && typeof err === "object" && "code" in err && (err as { code: number }).code === 16 ) { sessionStorage.setItem(SESSION_EXPIRED_KEY, "1"); clearTokens(); window.location.href = "/login"; } throw err; } }; /** Authenticated transport — used for all services except login */ const transport = createGrpcWebTransport({ baseUrl: API_URL, interceptors: [authInterceptor], }); /** Public transport — no auth header, used for login/refresh */ const publicTransport = createGrpcWebTransport({ baseUrl: API_URL, }); // --------------------------------------------------------------------------- // Service clients // --------------------------------------------------------------------------- export const authClient = createClient(AuthService, publicTransport); export const tradingClient = createClient(TradingService, transport); export const riskClient = createClient(RiskService, transport); export const mlClient = createClient(MLService, transport); export const mlTrainingClient = createClient(MLTrainingService, transport); export const configClient = createClient(ConfigService, transport); export const monitoringClient = createClient(MonitoringService, transport); export const backtestingClient = createClient(BacktestingService, transport);