/**
 * Service Definition for the authorization capability seam (`ctx.authorization`):
 * obtaining a credential nobody can supply from configuration alone, because
 * getting it requires a conversation with the human — open this page, paste
 * that code, pick an account.
 *
 * The seam owns the conversation and the lifecycle; it never owns the protocol.
 * A plugin that knows how to obtain its own credential registers a flow keyed
 * by the `CredentialKey` that flow writes, and the flow talks to whatever
 * surface started it through one neutral vocabulary of notices and prompts. So
 * a second authorization protocol arrives as another flow rather than as
 * another seam, and a surface that renders one flow renders all of them.
 *
 * ```ts
 * const dispose = ctx.authorization.registerFlow({
 *   key: credentialKey('llm-pi-ai', 'openai-codex'),
 *   label: 'ChatGPT (Codex)',
 *   methods: [{ id: 'oauth', label: 'Sign in with ChatGPT' }],
 *   async run(session) {
 *     session.notify({ message: 'Continue in your browser', url })
 *     await commitThroughCredentials(await exchange(session.signal))
 *   },
 * })
 * ```
 *
 * @module @deepseek-ai/dsh-authorization
 */
import { Context, Service } from '@deepseek-ai/cordis';
import type { CredentialKey } from '@deepseek-ai/dsh-credentials';
import { HarnessError } from '@deepseek-ai/dsh-llm';
import type { AuthorizationEntry, AuthorizationMethod, AuthorizationNotice, AuthorizationOutcome, AuthorizationPrompt, AuthorizationSettlement } from './types.ts';
export type { AuthorizationEntry, AuthorizationMethod, AuthorizationNotice, AuthorizationOutcome, AuthorizationPrompt, AuthorizationPromptOption, AuthorizationSettlement, AuthorizationStatus, } from './types.ts';
declare module '@deepseek-ai/cordis' {
    interface Context {
        authorization: AuthorizationService;
    }
    interface Events {
        /**
         * One authorization attempt has finished and released its key. Fires for
         * every terminal outcome, failures included, so a surface watching a key it
         * did not start (a second browser tab) learns the attempt is over.
         * @mode emit
         * @param key - the credential record the finished attempt was authorizing.
         * @param settlement - how it ended, including the `failed` case its caller sees as a thrown error.
         */
        'authorization/settled'(key: CredentialKey, settlement: AuthorizationSettlement): void;
    }
}
/** Stable error taxonomy for authorization failures. */
export declare class AuthorizationError extends HarnessError {
    constructor(message: string, code: string, options?: ErrorOptions);
}
/**
 * The rejection an {@link AuthorizationInteraction.prompt} uses to say the
 * human declined — dismissed the question, chose not to answer — rather than
 * that the surface broke. An attempt whose flow fails after a prompt was
 * declined settles as `cancelled`, the same outcome as a withdrawn signal,
 * because the human saying no is a refusal, not a breakage. Only a human's
 * "no" may reject with this class: a prompt withdrawn by its own `signal` (a
 * flow retiring the losing question of a race) must reject with something
 * else, or a later genuine failure would be misread as a decline.
 */
export declare class AuthorizationDeclinedError extends AuthorizationError {
    constructor(message?: string);
}
/**
 * What a running flow is given to talk to the human. Every member is scoped to
 * one attempt: the flow neither knows nor chooses which surface is listening.
 */
export interface AuthorizationSession {
    /** The method id the caller picked, always one this flow declared. */
    readonly method: string;
    /** Aborted when the caller withdraws or `cancel()` is called for this key. */
    readonly signal: AbortSignal;
    /**
     * Report progress, or tell the human what to do next. Fire-and-forget: a
     * surface that cannot render a notice must not stall the flow.
     * @param notice - the message, and any page or code it refers to.
     */
    notify(notice: AuthorizationNotice): void;
    /**
     * Ask the human a question the flow cannot answer for itself.
     * @param prompt - what to ask, and how it should be presented.
     * @returns what the human typed, or the chosen option's id.
     * @throws when the human declines, or the prompt's own signal withdraws it.
     */
    prompt(prompt: AuthorizationPrompt): Promise<string>;
}
/**
 * A plugin's knowledge of how to obtain one credential. The flow owns the
 * write: `run()` resolving means the record for `key` is committed through
 * `ctx.credentials` during that run, which the seam confirms — a commit
 * observed within the attempt, still present after it — before reporting
 * success. Committing inside the flow is what lets a library that persists
 * through its own store adapter (pi-ai's `Models.login()`) stay the single
 * writer instead of being copied back out and written twice.
 */
export interface AuthorizationFlow {
    /** The credential record this flow writes. Its scope names the owning plugin. */
    readonly key: CredentialKey;
    /** User-facing name of what is being authorized. */
    readonly label: string;
    /**
     * The methods offered, most preferred first; a caller naming none gets the
     * first. Typed non-empty because a flow with nothing to run is a flow that
     * cannot be begun, and the type says so at the one place flows are written.
     */
    readonly methods: readonly [AuthorizationMethod, ...AuthorizationMethod[]];
    /**
     * Run one attempt to obtain and commit the credential.
     * @param session - the chosen method, the cancellation signal, and the interaction callbacks.
     * @returns once the record is committed.
     * @throws when the attempt fails or the human declines.
     */
    run(session: AuthorizationSession): Promise<void>;
}
/**
 * The surface half of one attempt. Supplied with the request rather than
 * registered, because the caller that starts an authorization is the one that
 * can talk to the human about it: prompts reach exactly the page that asked,
 * and a headless caller supplies an interaction that declines.
 */
export interface AuthorizationInteraction {
    /**
     * Render a notice from the running flow.
     * @param notice - the message, and any page or code it refers to.
     */
    notify(notice: AuthorizationNotice): void;
    /**
     * Put a question to the human and wait.
     * @param prompt - what to ask, and how it should be presented.
     * @returns the typed text, or the chosen option's id.
     * @throws {AuthorizationDeclinedError} when the human declines; any other
     *   rejection reads as the surface failing, not as an answer.
     */
    prompt(prompt: AuthorizationPrompt): Promise<string>;
}
/** One request to authorize a key. */
export interface AuthorizationRequest {
    /** The credential record to authorize; a flow must be registered for it. */
    key: CredentialKey;
    /** Which of the flow's methods to run. Defaults to the flow's first. */
    method?: string;
    /** The surface that will render this attempt's notices and prompts. */
    interaction: AuthorizationInteraction;
    /** Withdraws the whole attempt. */
    signal?: AbortSignal;
}
/**
 * `ctx.authorization`: a registry of credential-obtaining flows, one attempt at
 * a time per key.
 */
export declare class AuthorizationService extends Service {
    /** The commit this seam confirms is a credential-record write, so the store is required, not optional. */
    static inject: string[];
    private readonly flows;
    private readonly running;
    constructor(ctx: Context);
    /**
     * Offer a way to obtain one credential. One flow per key: two plugins
     * claiming the same key would each write a record in their own format, and
     * whichever ran last would leave the other reading a payload it cannot parse.
     *
     * @param flow - the key it writes, its label, its methods, and its runner.
     * @returns Disposer that withdraws this flow.
     * @throws {AuthorizationError} code `DUPLICATE_FLOW` when the key is already claimed.
     */
    registerFlow(flow: AuthorizationFlow): () => void;
    /**
     * Every registered flow, for a surface listing what can be authorized.
     * @returns one entry per flow, in registration order.
     */
    list(): readonly AuthorizationEntry[];
    /**
     * One registered flow.
     * @param key - the credential record to ask about.
     * @returns the entry, or undefined when no flow claims that key.
     */
    describe(key: CredentialKey): AuthorizationEntry | undefined;
    /** The public view of one registered flow. */
    private entry;
    /**
     * Withdraw the attempt running for a key, if any. Separate from the
     * request's own signal because a request/response transport answers a Cancel
     * button on a second call, with no handle on the first one's signal.
     * @param key - the credential record whose attempt should stop.
     */
    cancel(key: CredentialKey): void;
    /**
     * Run one attempt to authorize a key, and report how it ended.
     *
     * One attempt per key at a time. A second caller is refused rather than
     * joined: the two would be prompting different humans through the same flow,
     * and the second would answer questions the first was asked.
     *
     * @param request - the key, the method, the surface, and the cancel signal.
     * @returns `authorized` once the flow's record is committed during this
     *   attempt and observed, or `cancelled` when the human declined or the
     *   caller withdrew.
     * @throws {AuthorizationError} code `NO_FLOW` when nothing claims the key,
     *   `UNKNOWN_METHOD` when the named method is not one the flow offers,
     *   `ALREADY_IN_FLIGHT` when an attempt is already running for the key, or
     *   `NOT_COMMITTED` when the flow resolved without committing a record
     *   during the attempt.
     */
    begin(request: AuthorizationRequest): Promise<AuthorizationOutcome>;
    /**
     * Fan `authorization/settled` out with contained listener failures: every
     * listener runs, and a sync throw or async rejection is logged without
     * changing the finished attempt's own outcome — except `INVARIANT`-coded
     * failures, which rethrow after every listener ran. The attempt is already
     * over and its key released when this fires, so a broken watcher (that
     * second browser tab) can never turn the caller's settled result into a
     * failure of its own.
     */
    private settle;
    /** Contained-listener diagnostic shared by the sync and async failure paths. */
    private warnSettledListenerFailure;
    /** Run the flow, then hold it to its half of the commit contract. */
    private attempt;
}
export default AuthorizationService;
//# sourceMappingURL=index.d.ts.map