Spaces:
Running
Running
File size: 3,509 Bytes
9a9d18a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
import React, {
createContext,
useContext,
useState,
useEffect,
ReactNode,
} from "react";
interface ApiContextType {
baseUrl: string;
wsBaseUrl: string;
isNgrokEnabled: boolean;
setNgrokUrl: (url: string) => void;
resetToLocalhost: () => void;
ngrokUrl: string;
getHeaders: () => Record<string, string>;
fetchWithHeaders: (url: string, options?: RequestInit) => Promise<Response>;
}
const ApiContext = createContext<ApiContextType | undefined>(undefined);
const DEFAULT_LOCALHOST = "http://localhost:8000";
const DEFAULT_WS_LOCALHOST = "ws://localhost:8000";
interface ApiProviderProps {
children: ReactNode;
}
export const ApiProvider: React.FC<ApiProviderProps> = ({ children }) => {
const [ngrokUrl, setNgrokUrlState] = useState<string>("");
const [isNgrokEnabled, setIsNgrokEnabled] = useState<boolean>(false);
// Load saved ngrok configuration on mount
useEffect(() => {
const savedNgrokUrl = localStorage.getItem("ngrok-url");
const savedNgrokEnabled = localStorage.getItem("ngrok-enabled") === "true";
if (savedNgrokUrl && savedNgrokEnabled) {
setNgrokUrlState(savedNgrokUrl);
setIsNgrokEnabled(true);
}
}, []);
const setNgrokUrl = (url: string) => {
// Clean and validate the URL
let cleanUrl = url.trim();
if (cleanUrl && !cleanUrl.startsWith("http")) {
cleanUrl = `https://${cleanUrl}`;
}
// Remove trailing slash
cleanUrl = cleanUrl.replace(/\/$/, "");
setNgrokUrlState(cleanUrl);
setIsNgrokEnabled(!!cleanUrl);
// Persist to localStorage
if (cleanUrl) {
localStorage.setItem("ngrok-url", cleanUrl);
localStorage.setItem("ngrok-enabled", "true");
} else {
localStorage.removeItem("ngrok-url");
localStorage.removeItem("ngrok-enabled");
}
};
const resetToLocalhost = () => {
setNgrokUrlState("");
setIsNgrokEnabled(false);
localStorage.removeItem("ngrok-url");
localStorage.removeItem("ngrok-enabled");
};
const baseUrl = isNgrokEnabled && ngrokUrl ? ngrokUrl : DEFAULT_LOCALHOST;
const wsBaseUrl =
isNgrokEnabled && ngrokUrl
? ngrokUrl.replace("https://", "wss://").replace("http://", "ws://")
: DEFAULT_WS_LOCALHOST;
// Helper function to get headers with ngrok skip warning if needed
const getHeaders = (): Record<string, string> => {
const headers: Record<string, string> = {
"Content-Type": "application/json",
};
// Add ngrok skip warning header when using ngrok
if (isNgrokEnabled && ngrokUrl) {
headers["ngrok-skip-browser-warning"] = "true";
}
return headers;
};
// Enhanced fetch function that automatically includes necessary headers
const fetchWithHeaders = async (
url: string,
options: RequestInit = {}
): Promise<Response> => {
const enhancedOptions: RequestInit = {
...options,
headers: {
...getHeaders(),
...options.headers,
},
};
return fetch(url, enhancedOptions);
};
return (
<ApiContext.Provider
value={{
baseUrl,
wsBaseUrl,
isNgrokEnabled,
setNgrokUrl,
resetToLocalhost,
ngrokUrl,
getHeaders,
fetchWithHeaders,
}}
>
{children}
</ApiContext.Provider>
);
};
export const useApi = (): ApiContextType => {
const context = useContext(ApiContext);
if (context === undefined) {
throw new Error("useApi must be used within an ApiProvider");
}
return context;
};
|