import type { Credential, CredentialInfo, CredentialStore } from '@earendil-works/pi-ai'; import { type ManagedProviderId, type SubscriptionCredential } from './subscription-state.js'; /** * Which pool account pi is handed for a managed provider. Deliberately dumb: pi calls `read()` * mid-turn, so this must be cheap, must not touch the network, and must not make a policy * decision that surprises a turn already in flight. First entry that is healthy and not cooling * wins; ties break on pool order, which is stable and user-controlled (`/provider-sub select` * promotes). * * When every account is cooling or auth-failed we still return the first one rather than * nothing: deciding a turn is unservable belongs to the rotation loop, and an `undefined` here * would make pi's eager launch gate FATAL a node that rotation could still have serviced. */ export declare function electPoolCredential(providerId: ManagedProviderId, now?: number): SubscriptionCredential | undefined; export declare class PoolCredentialStore implements CredentialStore { private readonly authPath; private readonly auth; constructor(authPath?: string); read(providerId: string): Promise; list(): Promise; /** * pi's locked read-modify-write, chiefly its OAuth refresh. The whole transaction — electing * the account, running pi's `fn`, committing the result — happens under the pool file's * cross-process lock, because a refresh token is single-use: two brokers electing the same * expired account outside a lock would both spend it and the loser would get a genuine * `invalid_grant`. Electing under the lock is also what guarantees the refreshed token lands * back on exactly the account whose token was spent. * * A managed provider with no pool account is NOT created here — pi must not be able to mint a * managed account behind crouter's login surfaces, which own the account-identity gate. */ modify(providerId: string, fn: (current: Credential | undefined) => Promise): Promise; delete(providerId: string): Promise; }