import { createClientTransport, type CredentialChainOptions } from "@hasna/contracts/client"; import { type HasnaStorageClient } from "@hasna/contracts/client/storage"; import type { ClientTransportResolution } from "@hasna/contracts/client"; /** The economy app slug used for the HASNA__* env lookups. */ export declare const ECONOMY_APP = "economy"; /** * The @hasna/contracts transport overrides (test injection: fetchImpl, headers, * timeout, retry, sleepImpl) plus the tier-1 credential chain options * (`--api-key` / `--profile` and the injectable `security` runner tests use). */ export type EconomyStorageClientOverrides = Parameters[2]; export type EconomyCloudStorage = { /** True when reads/writes must go to the cloud HTTP API. */ readonly active: true; /** The ready HTTP storage client. */ readonly client: HasnaStorageClient; } | { readonly active: false; readonly client: null; }; /** * Explicit local-store opt-in variables. The on-box SQLite store is served * only when one of these is set to a truthy value; without either of them (and * without a resolved credential) the client fails closed. */ export declare const LOCAL_STORAGE_OPT_IN_KEYS: readonly ["HASNA_ECONOMY_LOCAL", "ECONOMY_LOCAL"]; /** * Every env name that can configure an economy authority or credential, * resolver-derived — the one spelling the resolver itself looks for, so a * second copy can never fall behind it. */ export declare function economyAuthorityEnvKeys(): string[]; /** * Does the ENVIRONMENT itself configure an economy authority or credential? * * Deliberately narrower than "does a credential resolve": answering it must not * touch the Keychain or the filesystem, because doing so would defeat the * isolation the local-opt-in short-circuit exists to provide (the @hasna/todos * `local-opt-in.ts` pattern, owner directive 2026-09-04). It reads the env * dictionary and nothing else. * * A DECLARED-BUT-BLANK variable counts as absent HERE — a blank has always been * this package's spelling for "not configured", and helpers in the wild blank * rather than delete. It is NOT absent once we do go hosted: the resolver * refuses a blank loudly rather than falling through to another identity, which * is the behaviour that matters at that point. */ export declare function hasEconomyEnvAuthorityIntent(env: Record): boolean; /** * True when SOMETHING configures a hosted authority for economy: the * `HASNA_ECONOMY_API_URL` env key (or its legacy alias), the Keychain * `api-url` item, or the `~/.hasna/economy/config/credentials` file. * * It asks the SAME three sources, in the same order and through the same * @hasna/contracts entry points, that `createClientTransport` consults before * it falls back to the fleet gateway; the gateway default is deliberately NOT * one of them, because a default that always applies would make this always * true. It drives the fail-closed message's way-out branch: an opted-in run * with a configured authority is a half-applied hosted run, and the error says * so instead of inviting the operator to use a different dataset. */ export declare function hostedAuthorityConfigured(env: Record, options?: EconomyStorageClientOverrides): boolean; /** * The environment as the resolver should see it: every authority/credential * variable that is DECLARED BUT BLANK removed. * * A blank has always been this package's spelling for "not configured" — it is * how the CLI's spawned-process fixtures neutralise an inherited fleet * environment and how consumer fixtures still write it. @hasna/contracts takes * the opposite and, for its purposes, correct view: a declared-but-blank * credential is a misconfiguration it refuses loudly rather than resolving * around. Both are right at their own layer: a blank that means "unset" at the * economy seam is not a credential the operator named. */ export declare function economyResolverEnv>(env: T): T; /** * Build the resolver's inputs: the normalised environment AND the credential * options that keep the machine's Keychain tier reachable across it. * * Dropping a declared-but-blank variable hands @hasna/contracts a COPY, and * the resolver gates its ambient tiers on object identity (`env === process.env`, * or the registry symbol its own snapshot carries). A copy is, by that test, a * caller-built world — the hermetic seam — so the Keychain is outside it and * tier 3 turns itself off silently, dropping a station from its Keychain * identity to the next tier in the chain. The gate is decided HERE, on the * original env, and carried across as the documented `keychain.enabled` control * rather than being left to an identity test the copy cannot pass (hasna/apps#1788). */ export declare function economyResolverInputs>(env: T, credentials?: CredentialChainOptions): { env: T; credentials: CredentialChainOptions; }; /** * Resolve the authenticated economy HTTP storage client for this environment. * * There is no `local` branch here on purpose: a client never infers a local * dataset from missing configuration. When nothing resolves, the shared * resolver THROWS and the caller decides (see {@link resolveEconomyCloudStorage}). */ export interface ResolvedEconomyStorageClient { transport: "http"; client: HasnaStorageClient; resolution: ClientTransportResolution; } /** The one call the storage seam makes: resolve the http client from the env. */ export declare function resolveEconomyStorageClient(name: string, env: Record, overrides?: EconomyStorageClientOverrides): ResolvedEconomyStorageClient; /** * The one line a local run prints, so an unhosted run can never be mistaken for * a hosted one that came back empty (owner directive 2026-09-04). It goes to * stderr, so `--json` stdout stays machine-readable. */ export declare function localEconomyNotice(): string; /** * The fail-closed error for a run with no credential and no local opt-in. * * The message is the documentation surface: it carries the resolver's own * diagnostic (which names the Keychain item, the credentials file it looked * for, and `HASNA_ECONOMY_API_KEY`) and adds the local opt-in, which the shared * resolver cannot know about. */ export declare function credentialRequiredError(env: NodeJS.ProcessEnv, cause?: unknown): Error; /** * Resolve the economy client storage transport for the current environment. * * Returns `{ active: true, client }` only when @hasna/contracts resolves an * authenticated HTTP transport (a credential from any tier, authority defaulted * to the fleet gateway). Returns `{ active: false }` (local store) only when * the explicit local opt-in (`HASNA_ECONOMY_LOCAL=1` / `ECONOMY_LOCAL=1`) is * set AND no hosted authority or credential resolves. Throws in every other * unconfigured case — the error names the required API environment so a * missing-env run can never silently serve the local dataset. */ export declare function resolveEconomyCloudStorage(env?: NodeJS.ProcessEnv, overrides?: EconomyStorageClientOverrides): EconomyCloudStorage; /** * Memoized {@link resolveEconomyCloudStorage} for the process lifetime. * * A local-mode resolution (the explicit opt-in) announces itself on stderr with * one line, once per process, so an unhosted run is never mistaken for a hosted * one that came back empty (owner directive 2026-09-04). The notice goes to * stderr so `--json` stdout stays machine-readable. The memoization never * stalls a credential rotation: the @hasna/contracts transport behind a hosted * client re-resolves its credential on EVERY request, so a long-lived MCP * server or SDK consumer picks up a new key without a restart. */ export declare function economyCloudStorage(env?: NodeJS.ProcessEnv): EconomyCloudStorage; /** Test-only: drop the memoized resolution so a new env can be resolved. */ export declare function resetEconomyCloudStorageCache(): void; /** Active cloud storage (narrowed so `client` is non-null). */ export type ActiveEconomyCloudStorage = Extract; /** Query params accepted by the read helpers below. */ export type CloudQuery = Record; /** * Read a collection resource from the cloud API and return the extracted array * (the serve envelope's `data`/`items`). Used by the read commands (sessions, * top, breakdown, accounts) so they render cloud data — never the local store — * when the client is on the http transport. */ export declare function cloudListItems(storage: ActiveEconomyCloudStorage, resource: string, query?: CloudQuery): Promise; /** * Read a single (non-collection) resource and return the unwrapped `data` * payload (e.g. `/usage` -> `{ snapshots, summary }`). Falls back to the raw * body if the server does not use the `{ data }` envelope. */ export declare function cloudObject(storage: ActiveEconomyCloudStorage, path: string, query?: CloudQuery): Promise; /** * The transport decision, rendered for operators (the `economy status` / * `economy transport` surfaces and diagnostics). Reports WHERE the authority and * credential came from — never the credential value. */ export interface EconomyTransportAuthority { /** `/v1` base for the server API, or null when nothing resolved. */ baseUrl: string | null; /** An env key NAME, a Keychain reference, a file PATH, or `"default"`. */ apiUrlSource: string | null; /** An env key NAME, a Keychain reference, or a file PATH. Never a value. */ apiKeySource: string | null; /** Which tier of the credential chain supplied the key. */ apiKeyTier: string | null; /** Human-readable warning, or null. Never contains secret values. */ warning: string | null; } export interface EconomyTransportReport { ok: boolean; /** True when this process is a client of a resolved store (hosted or local). */ selected: boolean; transport: "http" | "sqlite"; /** `"local-opt-in"` for the explicit local lane, else the http transport source. */ source: string | null; authority: EconomyTransportAuthority | null; /** Human-readable issues when `ok` is false (the fail-closed refusal). */ issues: string[]; } /** * Resolve the economy transport and report the decision WITHOUT throwing. * * The one surface that must not fail the process on a missing credential: a * status command that throws would turn "tell me why I am unconfigured" into a * crash. Everything else calls {@link resolveEconomyCloudStorage} and fails * closed. */ export declare function economyTransportReport(env?: NodeJS.ProcessEnv, overrides?: EconomyStorageClientOverrides): EconomyTransportReport; //# sourceMappingURL=cloud-storage.d.ts.map