1import { runAtomCommand } from "@t3tools/client-runtime/state/runtime";
2import { readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff";
3
4import { toastManager } from "./components/ui/toast";
5import { appAtomRegistry } from "./rpc/atomRegistry";
6import { environmentPresentations } from "./state/presentation";
7import { serverEnvironment } from "./state/server";
8
9type ProviderAuthDelivery = NonNullable<ReturnType<typeof readCodexAuthDelivery>>;
10
11/**
12 * Remove the code before the router, tracing, or welcome screen sees the incoming address,
13 * then hand it to its environment once that environment connects. Hosted web receives only
14 * the one-time code; the selected environment verifies and stores tokens.
15 */
16export function startProviderAuthDelivery(): void {
17 if (!window.location.hash.startsWith("#codex-auth=")) return;
18 const delivery = readCodexAuthDelivery(window.location.href);
19 window.history.replaceState(
20 window.history.state,
21 "",
22 delivery?.returnUrl ?? `${window.location.pathname}${window.location.search}`,
23 );
24 if (!delivery) return;
25
26 const presentationAtom = environmentPresentations.presentationAtom(delivery.environmentId);
27 if (appAtomRegistry.get(presentationAtom)?.connection.phase === "connected") {
28 void completeProviderAuth(delivery);
29 return;
30 }
31 const unsubscribe = appAtomRegistry.subscribe(presentationAtom, (presentation) => {
32 if (presentation?.connection.phase !== "connected") return;
33 unsubscribe();
34 void completeProviderAuth(delivery);
35 });
36}
37
38async function completeProviderAuth(delivery: ProviderAuthDelivery): Promise<void> {
39 try {
40 const result = await runAtomCommand(
41 appAtomRegistry,
42 serverEnvironment.completeProviderAuth,
43 {
44 environmentId: delivery.environmentId,
45 input: {
46 instanceId: delivery.instanceId,
47 flowId: delivery.flowId,
48 callbackUrl: delivery.callbackUrl,
49 },
50 },
51 { reportFailure: false },
52 );
53 if (result._tag === "Failure") {
54 toastManager.add({
55 type: "error",
56 title: "ChatGPT sign-in couldn't finish",
57 description: "Return to the provider and try again.",
58 });
59 }
60 } catch {
61 toastManager.add({
62 type: "error",
63 title: "ChatGPT sign-in couldn't finish",
64 description: "Reconnect to the environment and try again.",
65 });
66 }
67}