/**
 * githubDeviceSignIn — let the REPORTER sign in, so the issue is filed as them.
 *
 *   import { githubDeviceSignIn } from 'agentfootprint/observe';
 *
 *   const signIn = await githubDeviceSignIn({ clientId: 'Iv1.0123456789abcdef' });
 *   show(`Go to ${signIn.verificationUri} and enter ${signIn.userCode}`);
 *   const { token, login } = await signIn.completed;   // resolves on authorize
 *
 * GitHub's OAuth **device flow**, spoken as three plain `fetch` calls and
 * nothing else: request a code, show it to the human, poll until they approve.
 * Zero dependencies, and it runs in a browser as well as on a server — there is
 * no client secret in this flow, which is exactly why it is the one that works
 * from a page.
 *
 * ## Why this exists beside a server token
 *
 * A server-side PAT files every report as the application. That is right for an
 * automated "Report a problem" button: the app owns the repo, the app owns the
 * token. It is wrong when the value is ATTRIBUTION — a field tester filing
 * upstream should appear as themselves, so a maintainer can ask them a
 * follow-up question and so their report counts as theirs.
 *
 * | | server PAT | device sign-in |
 * |---|---|---|
 * | Who the issue is from | the application | the reporter |
 * | Where the token lives | server environment | the reporter's session, in memory |
 * | Human steps | none | one: enter a code, approve |
 * | Right for | in-app "report a problem" | field testers filing upstream |
 *
 * The token this returns is handed to {@link githubBugReporter} as `token`,
 * with no special-casing anywhere: a token is a token.
 *
 * ## Keep it in memory, for the session only
 *
 * **Never `localStorage`, never a cookie, never a log line.** A device-flow
 * token is a live credential for the account that approved it; persisting it in
 * a browser turns one XSS into a lasting account compromise. Hold it in a
 * variable, use it, drop it when the tab closes.
 *
 * ## Scopes are coarse here, and that is GitHub's design
 *
 * The device flow issues a CLASSIC OAuth token, and classic scopes are coarse:
 * `public_repo` (the default here) grants write across every public repository
 * the account can reach, and `repo` grants it across private ones too. There is
 * no fine-grained equivalent in this flow. That trade buys attribution — the
 * issue is really from that person — and it is the reason the default stops at
 * `public_repo`: filing an issue needs no more, and the token disappears with
 * the session. Where least privilege matters more than attribution, use a
 * fine-grained PAT on a server instead (see {@link githubBugReporter}).
 *
 * ## The collaborator caveat, stated rather than discovered
 *
 * A reporter who signs in as themselves can file an issue on a public repo, and
 * can commit evidence ONLY to a repository they can write to. Pointing
 * `evidenceRepo` at a private repo the reporter is not a collaborator on will
 * fail with a 404 (GitHub hides private repos from tokens that cannot see
 * them). Either add the reporter as a collaborator, or let them attach the zip
 * to the issue by hand — `exportBugReport` gives them the file either way.
 *
 * ## Secrecy
 *
 * The token appears in no message this module can produce. The three failure
 * shapes of the flow — the human denied it, the code expired, the poll was
 * aborted — are named plainly, with GitHub's `error_description` only, never a
 * response body or a request.
 */
export interface GithubDeviceSignInOptions {
    /**
     * The OAuth App's client id. **Public by design** — the device flow has no
     * client secret, so this belongs in your front-end code. Create the app once
     * under the organisation, tick "Enable Device Flow", and copy the id.
     */
    readonly clientId: string;
    /**
     * Classic OAuth scopes. Default `['public_repo']` — enough to file an issue
     * and commit to a public evidence repo, and no more. `['repo']` is what a
     * private evidence repo needs, and it is a much larger grant; ask for it only
     * when the flow really commits there.
     */
    readonly scopes?: readonly string[];
    /** Cancel the polling (a closed dialog, an unmounted component). */
    readonly signal?: AbortSignal;
    /** GitHub's web origin. GHES: `https://github.your-company.com`. */
    readonly authBase?: string;
    /** GitHub's API root. GHES: `https://github.your-company.com/api/v3`. */
    readonly apiBase?: string;
    /** Test seam — inject `fetch`. Bypasses the network entirely. */
    readonly _fetch?: typeof fetch;
    /** Test seam — inject the wait between polls. */
    readonly _sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
}
/** Who signed in, and with what. */
export interface GithubDeviceIdentity {
    /** The access token. Memory-only; see the module docs. */
    readonly token: string;
    /** Usually `bearer`. */
    readonly tokenType: string;
    /** The scopes GitHub actually granted — not necessarily the ones asked for. */
    readonly scopes: readonly string[];
    /** The GitHub login the issue will be filed as. `undefined` if `/user` refused. */
    readonly login?: string;
}
/** The code to show a human, and the promise that resolves when they approve. */
export interface GithubDeviceSignIn {
    /** The code the human types — show it verbatim, it is case-sensitive. */
    readonly userCode: string;
    /** The page they type it into. */
    readonly verificationUri: string;
    /** Seconds until `userCode` stops working. */
    readonly expiresIn: number;
    /** Seconds GitHub asked us to wait between polls. */
    readonly interval: number;
    /**
     * Resolves when the human approves, rejects when they deny it, when the code
     * expires, or when `signal` aborts. Polling starts immediately — awaiting
     * this later does not miss an approval.
     */
    readonly completed: Promise<GithubDeviceIdentity>;
}
/**
 * Start a device-flow sign-in.
 *
 * Resolves as soon as GitHub hands back a code — that is the point, because
 * the human cannot approve a code they have not been shown. The waiting happens
 * on the returned `completed` promise.
 *
 * @throws TypeError when `clientId` is missing (naming where it comes from).
 * @throws Error naming the status when GitHub refuses to issue a code.
 */
export declare function githubDeviceSignIn(options: GithubDeviceSignInOptions): Promise<GithubDeviceSignIn>;
