import type Database from 'better-sqlite3';
import { RemoteHttpClient, type GetProjectResponse } from './remote-http-client.js';
import type { DeviceLoginPollResponse, DeviceLoginStartResponse, RemoteAccountResponse } from '../../shared/remote-account.js';
/** Input to `RemoteAuthService.pushBundle` — bytes-derived values come from M17. */
export interface PushBundleInput {
    tarGzPath: string;
    sizeBytes: number;
    sha256: string;
    /** Sent as `X-Project-Name` on first push (config.name). */
    projectName: string;
    /** `null` ⇒ first push (create project); a UUID ⇒ subsequent push. */
    remoteProjectId: string | null;
}
/** Unified outcome from a push, regardless of first vs subsequent endpoint. */
export interface PushBundleOutcome {
    remoteProjectId: string;
    remoteReleaseId: string;
    remoteReleaseSequence: number;
    deduplicated: boolean;
}
/**
 * M24 — authenticates c4s against the remote API via OAuth Device Authorization
 * Grant. Login is a human action (no MCP tool): the agent never logs in or
 * touches the device flow. The token is an operational secret kept in
 * `remote_session` and never returned to the UI.
 */
export declare class RemoteAuthService {
    private db;
    private client;
    private flow;
    constructor(db: Database.Database, client: RemoteHttpClient);
    /** POST /api/remote-account/login/start. */
    startDeviceFlow(): Promise<DeviceLoginStartResponse>;
    /** POST /api/remote-account/login/poll. */
    pollDeviceFlow(): Promise<DeviceLoginPollResponse>;
    /** GET /api/remote-account. Never exposes access_token. */
    getCurrentAccount(): RemoteAccountResponse;
    /** POST /api/remote-account/logout. Idempotent; also aborts an in-flight device flow. */
    logout(): RemoteAccountResponse;
    /**
     * M26 §4 consumer entry point — fetch the remote project for the
     * `/api/remote-project` proxy. Bearer OPTIONAL since 0.1.32: anonymous and
     * non-owner readers also reach the card (with the public subset). The
     * service is still the single owner of Bearer injection + 401 wipe.
     *
     * Returns:
     *  - `{ kind: 'ok', project }` on 200 (project carries `isOwner`, `description`).
     *  - `{ kind: 'not_found' }` on remote 404 (route surfaces `reason: 'not_found'`).
     *
     * Throws `RemoteUnauthorizedError` after wiping the session on 401 (only
     * possible when a bearer was sent; route maps to 502 SESSION_EXPIRED).
     * Rethrows `RemoteRequestError` on other transport errors / 5xx (route maps
     * to 502 REMOTE_UNAVAILABLE).
     */
    getRemoteProject(remoteProjectId: string): Promise<{
        kind: 'ok';
        project: GetProjectResponse;
    } | {
        kind: 'not_found';
    }>;
    /**
     * 0.1.32 M25 §1a consumer entry point — PATCH the remote project's name and/or
     * description. Owner-only (peer enforces; we gate the call on a present
     * session so the bearer is available). 401 wipes the session row before
     * rethrowing; the route maps that to 502 SESSION_EXPIRED.
     */
    updateRemoteProject(remoteProjectId: string, body: {
        name?: string;
        description?: string | null;
    }): Promise<GetProjectResponse>;
    /**
     * M25 consumer entry point — transports a release bundle to the remote with the
     * Bearer injected from the local session. First push (`remoteProjectId === null`)
     * creates the project; subsequent pushes append a release. The access_token never
     * leaves M24. On 401 the single-row `remote_session` is atomically wiped (same as
     * logout) and the `RemoteUnauthorizedError` is re-thrown for M25 to map to 502.
     */
    pushBundle(input: PushBundleInput): Promise<PushBundleOutcome>;
    private readSession;
    /**
     * Fetch the account profile (email/status), then atomically replace the
     * single `remote_session` row. Profile-first so a failed enrich never leaves
     * a half-written row; a 401 here means the freshly-issued token was already
     * rejected — surface as unauthenticated without persisting.
     */
    private persistSession;
}
