import { createContext } from "react"; import { useQuery } from "@tanstack/react-query"; // Sign-In With GPG (SIWG) is a SEPARATE, connection-free signer: unlike a wallet // there is nothing to "connect" first — the user signs a challenge in their terminal // and pastes the result back. This module deliberately pulls in NO wagmi/viem, so it // can later move into a standalone `@multiplatform.one/gpg` package on top of connectkit. export const GpgStatusState = { READY: "ready", LOADING: "loading", SUCCESS: "success", ERROR: "error", } as const; export type GpgStatusState = (typeof GpgStatusState)[keyof typeof GpgStatusState]; export type GpgConfig = { // Required: fetch a fresh nonce from the backend (e.g. keycloak /realms//wallet/nonce). getNonce: () => Promise; // Required: submit the signed credential. The screen produces // username = base64(armoredSignature + armoredPublicKey) // password = base64(message) // For a keycloak browser login this writes the login form and submits it (the page // then navigates); an API consumer may POST and return a boolean instead. onSign: (cred: { username: string; password: string; message: string; }) => Promise | boolean | void; // Required: the challenge the user signs. Build it with mpo web3's // buildWalletMessage("gpg", ...); web3's GpgProvider passes that by default. buildMessage: (args: { nonce: string }) => string; enabled?: boolean; // Background nonce refetch. Default `false`: the challenge MUST stay byte-stable from // sign to submit (a refetch recomputes `message` and desyncs it from the signature). nonceRefetchInterval?: number | false; // Called with a listener on mount; the provider refetches its nonce whenever the // listener fires (e.g. keycloakWallet's resetNonce once a sign-in consumed it). // Returns the unsubscribe. subscribeNonceReset?: (listener: () => void) => () => void; }; export type GpgContextValue = Required< Pick > & { subscribeNonceReset?: GpgConfig["subscribeNonceReset"]; nonce: ReturnType>; // Derived from the nonce — what the user copies/signs, and the ready-to-run command. message: string | null; command: string | null; status: GpgStatusState; signIn: (pastedBlob: string) => Promise; resetStatus: () => void; }; export const GpgContext = createContext(null);