UNPKG

@capgo/cli

Version:
166 lines (165 loc) 6.76 kB
export declare const GOOGLE_OAUTH_SCOPES_ANDROIDPUBLISHER: readonly ["openid", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/androidpublisher"]; export interface GoogleOAuthConfig { clientId: string; /** * Desktop clients receive a "secret" from the Console that isn't truly * confidential; pass it when available — Google accepts the token exchange * with or without it as long as PKCE is used. */ clientSecret?: string; scopes: readonly string[]; /** Extra params to include on the auth URL (e.g. `login_hint`, `prompt`). */ extraAuthParams?: Record<string, string>; } export interface GoogleOAuthTokens { accessToken: string; refreshToken?: string; /** * Unix epoch in milliseconds — the wall-clock time the access token stops * being accepted. Callers should refresh before this. */ expiresAt: number; idToken?: string; scope: string; tokenType: string; } export interface GoogleUserInfo { sub: string; email: string; emailVerified: boolean; name?: string; picture?: string; } export interface RunOAuthFlowOptions { /** * Called once with the authorization URL right before we open it. Useful * for logging the URL in case `open()` fails. */ onAuthUrl?: (url: string) => void; /** Called with user-visible status updates while we wait for the redirect. */ onStatus?: (message: string) => void; /** Overall deadline for the whole flow. Defaults to 5 minutes. */ timeoutMs?: number; /** Abort the flow early — useful for React cleanup. */ signal?: AbortSignal; } export interface PkcePair { verifier: string; challenge: string; method: 'S256'; } /** * Generate a PKCE verifier (43–128 chars of unreserved URL chars) and its * SHA-256 challenge. The verifier must be held until the token exchange. */ export declare function generatePkcePair(): PkcePair; export declare function generateState(): string; export declare function buildAuthUrl(args: { clientId: string; redirectUri: string; scopes: readonly string[]; state: string; codeChallenge: string; extra?: Record<string, string>; }): string; interface RawTokenResponse { access_token: string; expires_in: number; refresh_token?: string; scope: string; token_type: string; id_token?: string; } export declare function parseTokenResponse(raw: RawTokenResponse, now?: number): GoogleOAuthTokens; /** Exchange an authorization code + PKCE verifier for tokens. */ export declare function exchangeAuthCode(args: { config: GoogleOAuthConfig; code: string; codeVerifier: string; redirectUri: string; }): Promise<GoogleOAuthTokens>; /** * Use a stored refresh token to mint a new access token. Refresh tokens may be * revoked by the user at any time; callers should surface a clean re-auth * prompt if this throws. */ export declare function refreshAccessToken(config: GoogleOAuthConfig, refreshToken: string): Promise<GoogleOAuthTokens>; /** Fetch the signed-in user's email and subject (stable Google ID). */ export declare function fetchUserInfo(accessToken: string): Promise<GoogleUserInfo>; /** * Revoke a Google OAuth token. Accepts either an access or refresh token — * revoking a refresh token also invalidates any access tokens minted from it. */ export declare function revokeToken(token: string): Promise<void>; /** * Error thrown by runOAuthFlow when the user approves the consent screen but * deselects one or more requested scopes. The CLI catches this specifically * to route the user back to a "please grant all permissions" re-sign-in step * instead of failing several phases later with confusing API errors. */ export declare class MissingScopesError extends Error { readonly missing: readonly string[]; readonly granted: string; constructor(missing: readonly string[], granted: string); } /** * Compare a space-separated `scope` string from a token response against the * scopes the CLI requested. Returns the subset of requested scopes that the * user did not grant. * * Google's tokeninfo response uses a space-separated, unordered list — the * order in `requestedScopes` is not preserved. Empty strings are filtered out. */ export declare function findMissingScopes(grantedScope: string, requestedScopes: readonly string[]): string[]; export interface LoopbackCallbackResult { /** Authorization code Google returned in the query string. */ code: string; /** * Finishes the browser response with the given HTML. Call this AFTER doing * the token exchange and scope validation so the user sees a result that * reflects the post-exchange state (e.g. "missing permissions") rather than * a generic "you can close this tab" page that's stale by the time it * matters. Idempotent — second call is a no-op. */ finishResponse: (html: string, statusCode?: number) => void; } /** * The shape returned by `startOAuthFlow`. The loopback server is already * running and the browser has been opened; the caller awaits `result` at a * later point (fire-and-poll pattern for MCP). */ export interface PendingOAuthSession { /** Full Google authorization URL that was opened in the browser. */ authUrl: string; /** The loopback redirect URI embedded in the authUrl. */ redirectUri: string; /** * Resolves with validated tokens once the browser callback lands, * code is exchanged and scopes pass. Rejects on error/timeout/missing-scopes. */ result: Promise<GoogleOAuthTokens>; /** Force-close the loopback server (safe after result settles). */ close: () => void; } /** * Non-blocking OAuth starter: opens the browser and starts the loopback * listener, then returns IMMEDIATELY without waiting for the sign-in to * complete. The caller can `await session.result` later to collect tokens. * * This is the foundation for the MCP fire-and-poll sign-in model. The Ink * wizard uses `runOAuthFlow` (which internally calls this and then awaits * `result`) to preserve its blocking behavior. */ export declare function startOAuthFlow(config: GoogleOAuthConfig, options?: RunOAuthFlowOptions): Promise<PendingOAuthSession>; /** * Run the full browser-based OAuth flow and return tokens. * * Side effects: * - Opens a browser window at Google's consent screen. * - Starts (and later stops) a loopback HTTP server on 127.0.0.1. * * Delegates to `startOAuthFlow` and awaits the result — preserving the * original blocking behavior Ink depends on. */ export declare function runOAuthFlow(config: GoogleOAuthConfig, options?: RunOAuthFlowOptions): Promise<GoogleOAuthTokens>; export {};