diff --git a/skyvern-frontend/src/store/useOptimisticallyRequestBrowserSessionId.ts b/skyvern-frontend/src/store/useOptimisticallyRequestBrowserSessionId.ts new file mode 100644 index 00000000..cf9bed0f --- /dev/null +++ b/skyvern-frontend/src/store/useOptimisticallyRequestBrowserSessionId.ts @@ -0,0 +1,65 @@ +import { create } from "zustand"; +import { AxiosInstance } from "axios"; + +export interface BrowserSessionData { + browser_session_id: string | null; + expires_at: number | null; // seconds since epoch +} + +interface OptimisticBrowserSessionIdState extends BrowserSessionData { + run: (client: AxiosInstance) => Promise; +} + +const SESSION_KEY = "skyvern.optimisticBrowserSession"; +const SESSION_TIMEOUT_MINUTES = 60; + +export const useOptimisticallyRequestBrowserSessionId = + create((set) => ({ + browser_session_id: null, + expires_at: null, + run: async (client) => { + const stored = localStorage.getItem(SESSION_KEY); + if (stored) { + try { + const parsed = JSON.parse(stored); + const { browser_session_id, expires_at } = parsed; + const now = Math.floor(Date.now() / 1000); // seconds since epoch + + if ( + browser_session_id && + typeof browser_session_id === "string" && + expires_at && + typeof expires_at === "number" && + now < expires_at + ) { + set({ browser_session_id, expires_at }); + return { browser_session_id, expires_at }; + } + } catch (e) { + // pass + } + } + + const resp = await client.post("/browser_sessions", { + timeout: SESSION_TIMEOUT_MINUTES * 60, // accepts seconds, so have to mult + }); + const { browser_session_id: newBrowserSessionId, timeout } = resp.data; + const newExpiresAt = Math.floor(Date.now() / 1000) + timeout * 0.9; + set({ + browser_session_id: newBrowserSessionId, + expires_at: newExpiresAt, + }); + localStorage.setItem( + SESSION_KEY, + JSON.stringify({ + browser_session_id: newBrowserSessionId, + expires_at: newExpiresAt, + }), + ); + + return { + browser_session_id: newBrowserSessionId, + expires_at: newExpiresAt, + }; + }, + }));