# `src/api` — Appmixer API client layer

The canonical way for CLI commands to talk to an Appmixer instance (gridd API).
Commands never make raw HTTP calls; every endpoint lives in a domain module here.

## Usage

```js
const api = require('./src/api');

// Uses the CLI config by default: `appmixer url` default + token stored by `appmixer login`.
const client = await api.createClient();

// Or explicit credentials (token is cached in-memory for 55 minutes per baseUrl+username):
const client2 = await api.createClient({ baseUrl, username, password });

// Pre-obtained token (or APPMIXER_TOKEN) — CI, and SSO sessions from `appmixer login --sso`.
const client3 = await api.createClient({ baseUrl, token });

// Pre-login endpoints (SSO discovery/redirect/auth) — no Authorization header:
const publicClient = api.createPublicClient(baseUrl);

const flows = await api.flows.listFlows(client, { limit: 10 });
```

Resolution order:

- `baseUrl`: explicit param → `APPMIXER_API_URL` env → default URL from `appmixer url`.
- auth: explicit `token` → `APPMIXER_TOKEN` env → `username`/`password` (`POST /user/auth`) →
  token stored by `appmixer login`.

## Module style: CommonJS

The CLI is CommonJS (commander v2, `require` everywhere). The client was ported from the
ESM `appmixer-skills/skills/_shared/appmixerApi` to CJS — no ESM boundary, so any command
can `require('./src/api')` directly. Keep new domain modules CJS.

## Error handling

All HTTP errors are thrown as `ApiError` (see `error.js`): the server message is surfaced
in `err.message`, and `err.status`, `err.data`, `err.method`, `err.url` are available.
`err.toJSON()` returns a `--json` friendly shape. Network errors (no response) have
`status === undefined`.

## What remains in `dist/` (and why)

`dist/index.js` is an ncc bundle of appmixer-core engine internals, hand-built in
appmixer-core via `cd engine && npm run build-appmixer-cli` (entry:
`engine/src/appmixer-cli-dep.js`) and copied into this repo. After the GridDriver
migration, **no CLI command uses GridDriver (or raw HTTP) for API calls** — all
HTTP goes through this `src/api` layer. The bundle is still needed for engine
logic that is not an API call:

- **Local component runtime** — `ComponentFactory`, `Flow`, `Message`,
  `ContextHandler`, `DevGridDriverUtils`, `DevPollingTimer`, `MessageLogger`,
  `DependencyContainer`: used by `appmixer test component` to run a component
  locally. This is the one remaining consumer of `GridDriver`
  (via `utils.getGridDriver`), because `DevGridDriverUtils` wraps it for
  context-store/static-call features during local runs.
- **Grid validator + JSON schemas** — used by `pack`, `publish`, `init component`.
- **Auth tooling** — `ServiceFactory`, `Token`, `Account`: used by `test auth`.
- **Default modifiers/categories** — used by `modifiers restore`.

Follow-up (tracked in the epic): drop the `GridDriver` export from
`appmixer-cli-dep.js` in appmixer-core once the local component runtime no longer
needs it, then rebuild `dist/`.

## Adding a new domain module

1. Create `src/api/<domain>.js` (`'use strict'`, CJS). One exported async function per
   endpoint, taking the axios `client` as the first argument and returning the parsed
   response body:

   ```js
   const listWidgets = async (client, query = {}) => {
       const { data } = await client.get('/widgets', { params: query });
       return data;
   };
   module.exports = { listWidgets };
   ```

2. Do not catch errors in the module — the client's response interceptor already maps
   them to `ApiError`.
3. Export the module from `src/api/index.js`.
4. Add tests in `test/api/<domain>.test.js` using the fake gridd server helper
   (`test/api/support/fake-gridd.js`) — assert the request method/path/query/body shape
   and that the response body is returned as-is.
5. Document non-obvious endpoint semantics in the function's JSDoc (source of truth:
   `appmixer-core/gridd/routes`).
