Files
zeekay 8986f49be0 the client carries the credential, because the document declares it
cloud's openapi.yaml now has a `bearer` securityScheme and a top-level
`security`, so regenerating turns 2498 operations from "imports
setBearerAuthToObject and calls it nowhere" into a real
`Authorization: Bearer` write from `configuration.accessToken`. The four
operations marked `security: []` — /v1/models, /v1/models/providers,
/v1/commands, /v1/openapi.json — generate no auth call, so commands-api.ts
is the one api file of 192 without one.

That retires `baseOptions: { headers: { Authorization } }`, which existed
only because a document with no scheme made `accessToken` inert. One field,
one header, one way; examples/client.ts and the docs say so.

examples/models is new and needs no credential, so a reader can run the
client against the live API before holding a key. Measured, not assumed:
models prints 112 models anonymously, hello prints
`sub admin/hanzo-cloud in org hanzo` with an IAM client-credentials token
and 401 invalid_token with a bad one, and money reads the org's own balance
where anonymous reads account "anonymous".

.spec-lock: hanzoai/cloud@113cf7d6, sha256 a50fc96c.
2026-08-14 17:21:07 -07:00

49 lines
2.0 KiB
TypeScript

// Where the API is, who we are, and how to print a failure. Every flow imports
// this and nothing else configures a client.
import { Configuration } from 'hanzoai';
/** Default host. `HANZO_BASE_URL` overrides it (staging, a local cloud, a tunnel). */
export const basePath = process.env.HANZO_BASE_URL ?? 'https://api.hanzo.ai';
/** Fail on the unset variable rather than on the 401 it causes three frames later. */
export function apiKey(): string {
const key = process.env.HANZO_API_KEY;
if (!key) {
throw new Error('HANZO_API_KEY is not set — export an IAM access token or a cloud API key');
}
return key;
}
/**
* The credential goes in `accessToken`, and that is the only place it goes.
*
* The document declares one securityScheme — `bearer`, http/bearer — and a
* top-level `security: [bearer]`, so every operation that does not opt out with
* `security: []` now generates `await setBearerAuthToObject(header, config)`,
* which reads this field and writes `Authorization: Bearer <token>`. 2498 call
* sites across 191 of the 192 api classes.
*
* These examples used to set the header by hand through `baseOptions`, because
* a document with no securityScheme generates no auth code and `accessToken`
* was inert. That workaround is gone: one field, one header, one way.
*/
export const config = (): Configuration =>
new Configuration({ basePath, accessToken: apiKey() });
/** No credential. The four operations the document marks `security: []` take this. */
export const anon = (): Configuration => new Configuration({ basePath });
/**
* axios buries the server's message in `response.data`; the bare `.message` is
* always "Request failed with status code 4xx", which says nothing.
*/
export function fail(err: unknown): never {
const e = err as { response?: { status?: number; data?: unknown }; message?: string };
if (e.response) {
console.error(`HTTP ${e.response.status}:`, JSON.stringify(e.response.data));
} else {
console.error(e.message ?? err);
}
process.exit(1);
}