@hasna/domains
Version:
Domain portfolio, registrar, marketplace, and DNS management for AI agents — CLI + MCP + HTTP API + SDK, shared account API and PostgreSQL
96 lines • 5.03 kB
TypeScript
import type { ClientEnv, ClientTransportResolution, CredentialChainOptions, CredentialTier, HasnaStorageClient, ResolvedCredential } from "./client-types.js";
/** The app slug the shared client seam resolves credentials and authority for. */
export declare const DOMAINS_APP_NAME: "domains";
export { domainsAuthorityEnvKeys } from "./client-storage-policy.js";
/**
* 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 fixtures scrub an inherited environment and how wrappers spell
* `HASNA_DOMAINS_API_URL="${MAYBE_UNSET}"`. @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, and the mismatch is not hypothetical: an
* environment carrying a real `HASNA_DOMAINS_API_KEY` alongside a blank legacy
* alias — the exact shape a scrubbed-then-overridden fixture produces — is a
* complete, unambiguous configuration that would otherwise be refused for the
* alias nobody set. Normalising here keeps "blank means unset" true at the
* domains seam while leaving the resolver's stricter rule intact for
* everything it does receive: a value that is present is still policed, and
* two aliases that actually disagree still refuse.
*/
export declare function domainsResolverEnv<T extends ClientEnv>(env: T): T;
/** The env object and credential options a domains surface hands @hasna/contracts. */
export interface DomainsResolverInputs<T extends ClientEnv> {
/** The environment with every declared-but-blank authority variable removed. */
env: T;
/** The chain options, with the Keychain tier's ambient gate already decided. */
credentials: CredentialChainOptions;
}
/**
* Build the resolver's inputs: the normalised environment AND the credential
* options that keep the machine's Keychain tier reachable across it. See the
* module header for why the gate has to travel with the copy.
*
* An explicit `enabled` from the caller still wins, and an injected `run`
* (which @hasna/contracts already treats as "enabled") is left alone, so the
* hermetic seam tests rely on is untouched. When there is no blank to remove
* the inputs pass through by identity, exactly as before — the CLI hands the
* resolver `process.env` itself, never a copy.
*/
export declare function domainsResolverInputs<T extends ClientEnv>(env: T, credentials?: CredentialChainOptions): DomainsResolverInputs<T>;
/**
* Options a domains surface forwards to the shared resolver: tier-1 credential
* inputs and the Keychain-tier seam.
*/
export interface DomainsResolverOptions {
/** Tier-1 credential inputs (`--api-key` / `--profile`) and Keychain controls. */
credentials?: CredentialChainOptions;
}
/**
* The transport report a caller can see — sources, tier, authority — with no
* key value in it. `baseUrl` is the `<origin>/v1` base the resolver produced.
*/
export interface DomainsTransportReport {
transport: "http";
/** `<origin>/v1` base for the server API. */
baseUrl: string;
/** WHERE the API URL came from: env key NAME, Keychain reference, file PATH, or `"default"`. */
apiUrlSource: string;
/** WHERE the API key came from: env key NAME, Keychain reference, or file PATH. Never a value. */
apiKeySource: string;
/** Which tier of the credential chain supplied the key. */
apiKeyTier: CredentialTier;
}
/**
* Resolve the domains authority and credential through the shared chain,
* FRESH, and return both the report and the credential VALUE.
*
* Throws a fail-closed `Error` (prefixed `domains fails closed: …`) that names
* the canonical env pair when no credential resolves from any tier, when a
* deliberate tier cannot be honoured, or when the configured authorities
* disagree — never a quiet fall-through to local data.
*/
export declare function resolveDomainsTransport(env?: ClientEnv, options?: DomainsResolverOptions): {
report: DomainsTransportReport;
credential: ResolvedCredential;
};
/** A resolved HTTP storage client plus the decision that produced it. */
export interface ResolvedDomainsHttpClient {
transport: "http";
client: HasnaStorageClient;
resolution: ClientTransportResolution;
}
/**
* Resolve the authenticated domains HTTP client for this environment.
*
* The returned client resolves its credential FRESH on every request (the
* transport's per-request binding provider), so a key rotation heals a
* long-lived MCP server or daemon without a rebuild. Throws a fail-closed
* `Error` when no credential resolves from any tier — never a quiet
* fall-through to local data.
*/
export declare function resolveDomainsHttpClient(env?: ClientEnv, options?: DomainsResolverOptions): ResolvedDomainsHttpClient;
//# sourceMappingURL=domains-resolver.d.ts.map