/** * Brand credential resolution shared by every `scai brand` surface and * by `scai setup login brand`. * * Three layers: * - `resolveBrandOrgId` — the pure orgId-resolution rule. * - `resolveBrandClient` — reads the config, resolves the orgId, looks * up the `brand[orgId]` credential, and returns the API client * options a brand operation needs. * - `resolveBrandSecrets` — pulls the `{ clientId, clientSecret, * authority, audience }` quartet a token mint needs. Env-var * overrides take precedence over the config-and-keychain pair so * serverless callers (the showcase orchestrator) can drive brand * ops without an OS keychain. * * (`src/brand/recipe/client.ts` has a separate `resolveBrandClient` that * resolves from a sync `SyncContext` rather than CLI options — the sync * engine always carries an explicit environment, so it does not need * the fallbacks here.) */ import type { BrandApiClientOptions } from "./api/types.js"; import type { BrandCredential } from "../config/types.js"; /** * Resolve the Sitecore `organizationId` for a Brand credential. * Resolution order: * * 1. Explicit `orgId` (e.g. from `--org-id`). * 2. When an env was explicitly named — via `--environment-name` or a * configured `defaultEnvProfile` — that env profile's * `organizationId`. A named env is authoritative: we never fall * through to a different profile's org behind the operator's back. * 3. When no env was named: the first env profile that carries an * `organizationId`. A single-environment config resolves here with * no flag and no default — you don't have to designate a default * env just to use the brand surface. * * Fails with `INPUT_INVALID` when none of the above yields a value — * scai's Brand credentials are one-org-per-credential and we can't * act without an org key. * * Exported for unit testing the resolution branches. */ export declare const resolveBrandOrgId: (explicitOrgId: string | undefined, environments: Record, envName: string | undefined) => string; /** The slice of CLI options `resolveBrandClient` needs. */ export interface BrandClientResolveOptions { config?: string; environmentName?: string; orgId?: string; } /** * Resolve the `BrandApiClientOptions` a `scai brand` operation runs * against: read the config, resolve the orgId (see `resolveBrandOrgId`), * and look up the `brand[orgId]` credential. * * Throws `AUTH_BRAND_REQUIRED` when the org resolves but has no * registered credential — the operator must run `scai setup login brand` * first. */ export declare const resolveBrandClient: (options: BrandClientResolveOptions) => BrandApiClientOptions; /** * The `{ clientId, clientSecret, authority, audience }` a Brand-API * client-credentials mint needs, plus the tier that supplied each * field for diagnostics. */ export interface ResolvedBrandSecrets { clientId: string; clientSecret: string; authority: string; audience: string; /** * Which tier the **secret** came from. `"env"` means the * orchestrator-style override; `"keychain"` is the developer-laptop * default. The `clientId` / `authority` / `audience` may still come * from the config when the secret is from the env (one-shot override * of just the secret is supported and useful for short-lived CI * secrets paired with a config-pinned client). */ source: "env" | "keychain"; } export interface ResolveBrandSecretsOptions { /** Sitecore organization id — keys the `getBrandClientSecret` slot. */ orgId: string; /** `brand[orgId]` block from the root config — may be absent in serverless. */ credential?: BrandCredential; } /** * Resolve the secrets a Brand-API M2M mint needs, walking two tiers: * * 1. **Environment variables** (`SITECOREAI_BRAND_CLIENT_ID` + * `SITECOREAI_BRAND_CLIENT_SECRET`). Both must be present for this * tier to apply. `SITECOREAI_BRAND_AUTHORITY` and * `SITECOREAI_BRAND_AUDIENCE` are optional overrides that compose * with either tier. * 2. **Config + OS keychain** — the developer-laptop default: client * id from the `brand[orgId]` config block, secret from the keychain * (`getBrandClientSecret`). * * **Precedence:** env wins. Rationale — the env-var path is the * explicit, per-invocation override a serverless host (Vercel function, * CI runner) sets right before calling scai; treating it as the * higher-priority lookup means a host can swap credentials between * invocations without touching disk or the keychain. The keychain path * is the long-lived default for human developers. * * Error contract — `AUTH_BRAND_REQUIRED` in three flavors so operators * know which knob to turn: * * - **Partial env**: one of `SITECOREAI_BRAND_CLIENT_ID` / * `SITECOREAI_BRAND_CLIENT_SECRET` is set but the other isn't. * We treat that as malformed (operator intended env-tier but * missed a var) rather than silently falling through to the * keychain — silent fallthrough would mask a typo and hand the * wrong credential to the API. * - **No credential anywhere**: neither env nor keychain has the * secret, and the config has no `clientId` for the org. * - **Keychain only, no secret**: the config has a `clientId` but * the keychain lookup came back empty (re-login needed). * * Returns `undefined` only as a sentinel for the "no credential * anywhere" case so the caller can build the right hint with the * orgId in scope. Other malformed states throw immediately. */ export declare const resolveBrandSecrets: (options: ResolveBrandSecretsOptions) => Promise;