# Add a getApiBase() accessor

**Task**: AZ-452_refactor_api_base_accessor
**Name**: Extract `getApiBase()` for `/api/...` prefix
**Description**: Add a thin accessor that prepends an optional base URL to every API request. Default empty string preserves today's behavior. Tests and alternative deployments can supply `VITE_API_BASE_URL`.
**Complexity**: 3 points
**Dependencies**: None
**Component**: `src/api/client.ts`, `src/api/sse.ts`, `src/vite-env.d.ts`
**Tracker**: AZ-452
**Epic**: AZ-447

## Problem

`src/api/client.ts:44` and every `api.get('/api/...')` call site assume the SPA and the suite share the same nginx (production layout). There is no override hook for test scenarios that need to redirect API traffic to a different host (e.g., MSW handlers serving from a separate origin, or e2e runs targeting a specific suite revision).

## Outcome

- A `getApiBase()` function is exported from `src/api/client.ts`.
- `request()`, `refreshToken()`, and `createSSE()` prepend its result to the URL.
- Default `''` preserves every existing call site unchanged.
- Tests can override per build via `VITE_API_BASE_URL`.

## Scope

### Included
- New `getApiBase()` function in `src/api/client.ts`.
- Threading the value through `request()` + `refreshToken()` in `client.ts` and `createSSE()` in `sse.ts`.
- `.env.example` and `src/vite-env.d.ts` updated.

### Excluded
- Changing the `api.get` / `api.post` / `api.put` / `api.patch` / `api.delete` / `api.upload` signatures.
- Touching the auth header or 401-retry logic.

## Acceptance Criteria

**AC-1: Default preserves today's behavior**
Given `VITE_API_BASE_URL` is unset,
When `api.get('/api/admin/auth/me')` is invoked,
Then the fetch URL is `/api/admin/auth/me` (no prefix added).

**AC-2: Override is honored**
Given `VITE_API_BASE_URL=http://test-host:8080` at build time,
When `api.get('/api/admin/auth/me')` is invoked,
Then the fetch URL is `http://test-host:8080/api/admin/auth/me`.

**AC-3: SSE honors the same prefix**
Given `VITE_API_BASE_URL=http://test-host:8080`,
When `createSSE('/api/flights/1/live-gps', ...)` is invoked,
Then the `EventSource` URL is `http://test-host:8080/api/flights/1/live-gps?access_token=...`.

**AC-4: Type declaration present**
Given a build,
Then `ImportMetaEnv` declares `readonly VITE_API_BASE_URL: string | undefined`.

## Non-Functional Requirements

**Reliability**
- Default empty-string fallback MUST be used when the env var is undefined or empty — no exceptions thrown at module load.

**Security**
- Adhere to AC-O3 (`credentials:'include'` semantics) and AC-23 (refresh transparency). The override does not affect cookie scope — that is governed by nginx and the browser's same-origin policy.

## Blackbox Tests

| AC Ref | Initial Data / Conditions | What to Test | Expected Behavior | NFR References |
|--------|--------------------------|--------------|-------------------|----------------|
| AC-1   | env unset; `api.get('/api/...')` | Captured fetch URL | Path unchanged | Compat |
| AC-2   | env set; `api.get('/api/...')` | Captured fetch URL | Prefix applied | Test override |
| AC-3   | env set; `createSSE('/api/...')` | Captured EventSource URL | Prefix applied | Test override |
| AC-4   | Build run | `vite-env.d.ts` declaration | Present | Compat |

## Constraints

- The API surface of `api.{get,post,put,patch,delete,upload}` and `createSSE` MUST NOT change.
- The default branch MUST be `getApiBase() === ''` so no relative-path semantics regress.

## Risks & Mitigation

**Risk 1: Trailing-slash drift in env**
- *Risk*: Setting the env to `http://host/` produces `http://host//api/...`.
- *Mitigation*: Trim a trailing slash in `getApiBase()` before returning.

**Risk 2: SSE `access_token` placement**
- *Risk*: When the prefix is set, the existing `?access_token=` insertion in `createSSE` must still work for both `url.includes('?')` and not-includes cases.
- *Mitigation*: The existing branch logic handles both — re-check after the change.
