163 lines · 6.2 KB · TypeScript
RawDownload
import { useAuth } from "@clerk/react";import { findErrorTraceId } from "@t3tools/client-runtime/errors";import {  isAtomCommandInterrupted,  settlePromise,  squashAtomCommandFailure,} from "@t3tools/client-runtime/state/runtime";import { useState } from "react"; import { toastManager } from "../components/ui/toast";import { relayEnvironmentDiscovery } from "../state/relay";import { useAtomCommand } from "../state/use-atom-command";import {  linkPrimaryEnvironment as linkPrimaryEnvironmentAtom,  unlinkPrimaryEnvironment as unlinkPrimaryEnvironmentAtom,  updatePrimaryEnvironmentPreferences as updatePrimaryEnvironmentPreferencesAtom,} from "./linkEnvironmentAtoms";import { usePrimaryCloudLinkState } from "./primaryCloudLinkState";import { resolveRelayClerkTokenOptions } from "./publicConfig"; export interface CloudLinkDesiredState {  readonly managedTunnel: boolean;  readonly publish: boolean;} /** * Drives the primary environment's T3 Connect link. T3 Connect (managed * tunnel) and agent-activity publishing are independent capabilities backed by * a single relay link, so consumers express the full desired state and * `reconcileCloudState` applies it: unlink when neither is wanted, otherwise * (re)link with the mode the managed-tunnel bit implies and set the publish * preference. Re-linking only happens when the managed-tunnel mode actually * changes, so flipping publish alone is cheap. */export function useCloudLinkController() {  const { getToken, isSignedIn } = useAuth();  const refreshRelayEnvironments = useAtomCommand(relayEnvironmentDiscovery.refresh, {    reportFailure: false,  });  const linkPrimaryEnvironment = useAtomCommand(linkPrimaryEnvironmentAtom, {    reportFailure: false,  });  const unlinkPrimaryEnvironment = useAtomCommand(unlinkPrimaryEnvironmentAtom, {    reportFailure: false,  });  const updatePrimaryEnvironmentPreferences = useAtomCommand(    updatePrimaryEnvironmentPreferencesAtom,    { reportFailure: false },  );  const primaryCloudLinkState = usePrimaryCloudLinkState();  const [operationError, setOperationError] = useState<string | null>(null);   const reportUpdateFailure = (cause: unknown) => {    const message = cause instanceof Error ? cause.message : "Could not update T3 Connect access.";    const traceId = findErrorTraceId(cause);    console.error("[t3-connect] Could not update T3 Connect", { message, traceId, cause });    setOperationError(traceId ? `${message} Trace ID: ${traceId}` : message);    toastManager.add({      type: "error",      title: "Could not update T3 Connect",      description: message,      data: traceId        ? {            secondaryActionProps: {              children: "Copy trace ID",              onClick: () => void navigator.clipboard?.writeText(traceId),            },          }        : undefined,    });  };   // Older environment servers predate the managedTunnelActive field; for them a  // link always implies a managed tunnel, so fall back to `linked`.  const managedTunnelActive =    primaryCloudLinkState.data?.managedTunnelActive ?? primaryCloudLinkState.data?.linked ?? false;  const publishAgentActivity = primaryCloudLinkState.data?.publishAgentActivity ?? false;  const linked = primaryCloudLinkState.data?.linked ?? false;   const reconcileCloudState = async (desired: CloudLinkDesiredState): Promise<boolean> => {    setOperationError(null);    const target = primaryCloudLinkState.target;    if (!target) {      reportUpdateFailure(new Error("Local environment is not ready yet."));      return false;    }    const tokenResult = await settlePromise(() => getToken(resolveRelayClerkTokenOptions()));    const wantsLink = desired.managedTunnel || desired.publish;     // A failure after this point may follow a partially applied mutation (e.g.    // the link succeeded but the preference update did not), so every exit —    // success or failure — refreshes the rendered state to whatever the server    // actually holds now.    if (!wantsLink) {      // Unlink works without a relay token — a failed token read must not      // leave the user unable to turn T3 Connect off.      const unlinkResult = await unlinkPrimaryEnvironment({        target,        clerkToken: tokenResult._tag === "Success" ? (tokenResult.value ?? null) : null,      });      if (unlinkResult._tag === "Failure") {        if (!isAtomCommandInterrupted(unlinkResult)) {          reportUpdateFailure(squashAtomCommandFailure(unlinkResult));        }        primaryCloudLinkState.refresh();        return false;      }    } else {      if (tokenResult._tag === "Failure") {        reportUpdateFailure(squashAtomCommandFailure(tokenResult));        return false;      }      const clerkToken = tokenResult.value;      if (!clerkToken) {        reportUpdateFailure(new Error("Sign in to T3 Connect before enabling this."));        return false;      }      if (!linked || managedTunnelActive !== desired.managedTunnel) {        const linkResult = await linkPrimaryEnvironment({          target,          clerkToken,          mode: desired.managedTunnel ? "managed" : "publish_only",        });        if (linkResult._tag === "Failure") {          if (!isAtomCommandInterrupted(linkResult)) {            reportUpdateFailure(squashAtomCommandFailure(linkResult));          }          primaryCloudLinkState.refresh();          return false;        }      }      const prefResult = await updatePrimaryEnvironmentPreferences({        target,        publishAgentActivity: desired.publish,      });      if (prefResult._tag === "Failure") {        if (!isAtomCommandInterrupted(prefResult)) {          reportUpdateFailure(squashAtomCommandFailure(prefResult));        }        primaryCloudLinkState.refresh();        return false;      }    }     primaryCloudLinkState.refresh();    const refreshResult = await refreshRelayEnvironments();    if (refreshResult._tag === "Failure" && !isAtomCommandInterrupted(refreshResult)) {      reportUpdateFailure(squashAtomCommandFailure(refreshResult));      return false;    }    return true;  };   return {    isSignedIn,    linkState: primaryCloudLinkState,    linked,    managedTunnelActive,    publishAgentActivity,    operationError,    reconcileCloudState,  };}