UNPKG

@capgo/cli

Version:
135 lines (134 loc) 5.34 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; } /** * 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. */ export declare function runOAuthFlow(config: GoogleOAuthConfig, options?: RunOAuthFlowOptions): Promise<GoogleOAuthTokens>; export {};