"use client"; import { useEffect, useRef, useState } from "react"; import Script from "next/script"; import Hyperbeam from "@hyperbeam/web"; /** * Client half of /browser/:activityId. Auth + the cloud-API call go through * the same shared client the account pages use (window.BigApi from * /landing/bigapi.js — token cookies, nonce renewal), then the returned * embedUrl is mounted as a Hyperbeam session. Control permissions follow * options.adminToken exactly like the old SocialBrowser.js. */ type HyperbeamInstance = Awaited>; type HyperbeamOptions = NonNullable[2]>; type PermissionData = Parameters[1]; interface BigApiClient { getBrowserActivity(activityId: string): Promise<{ embedUrl: string; // The cloud API's options object feeds straight into Hyperbeam(); // adminToken may come back null (the old JS treated null as "viewer"). options: HyperbeamOptions & { adminToken?: string | null }; }>; } declare global { interface Window { BigApi?: BigApiClient; } } /* The activityId is the last path segment of /browser/:activityId. Read it from the URL client-side so this stays a static route (the host rewrites /browser/* here). */ function readActivityId(): string { if (typeof window === "undefined") return ""; const parts = window.location.pathname.split("/").filter(Boolean); const i = parts.indexOf("browser"); return i >= 0 && parts[i + 1] ? decodeURIComponent(parts[i + 1]) : ""; } export default function BrowserClient() { const videoRef = useRef(null); const started = useRef(false); const hbRef = useRef(null); const [apiReady, setApiReady] = useState(false); const [error, setError] = useState(""); useEffect(() => { if (!apiReady || started.current) return; const activityId = readActivityId(); if (!activityId) { setError("Missing browser session."); return; } started.current = true; const start = async () => { try { const session = await window.BigApi!.getBrowserActivity(activityId); if (!videoRef.current) return; const options: HyperbeamOptions = { ...session.options, adminToken: session.options.adminToken ?? undefined, }; const hb = await Hyperbeam(videoRef.current, session.embedUrl, options); hbRef.current = hb; // Admins control the shared browser; everyone else watches. (Partial // permission updates are what the old site sent; the SDK's type wants // the full object but the API accepts partials.) hb.setPermissions(hb.userId, { control_disabled: !session.options.adminToken, } as PermissionData); } catch (e) { console.error(e); setError("Could not start the browser session. The link may have expired."); } }; start(); return () => { hbRef.current?.destroy(); hbRef.current = null; }; }, [apiReady]); return ( <>