# 01 — API Transport ## 1. High-Level Overview **Purpose**: Thin wrappers over the browser's `fetch` and `EventSource` that every feature uses to talk to the suite backend. Sole owners of cookie / bearer / refresh-token plumbing on the wire. **Architectural Pattern**: HTTP/SSE facade. No service-specific clients — every feature passes string URLs directly. **Upstream dependencies**: `00_foundation` (types). **Downstream consumers**: `02_auth`, `03_shared-ui` (FlightContext, DetectionClasses), `05_flights`, `06_annotations`, `07_dataset`, `08_admin`, `09_settings`. ## 2. Internal Interfaces ### `src/api/client.ts` | Export | Signature | Notes | |--------|-----------|-------| | `api.get(url, opts?): Promise` | thin `fetch` wrapper | Adds `credentials: 'include'`, parses JSON, throws on non-2xx | | `api.post(url, body?, opts?): Promise` | same | | | `api.put(url, body?, opts?): Promise` | same | | | `api.del(url, opts?): Promise` | same | | | `ApiError` | error class | Thrown with `{ status, body }` on non-2xx | ### `src/api/sse.ts` | Export | Signature | Notes | |--------|-----------|-------| | `subscribe(url, onMessage, onError?): { close }` | factory | Creates `EventSource` with the **bearer token in the query string** (browser `EventSource` can't set headers). Returns a `close()` handle. | ### `src/api/endpoints.ts` (since AZ-486 / F7) | Export | Signature | Notes | |--------|-----------|-------| | `endpoints` | `Readonly<{ admin, annotations, flights, detect }>` of typed builder functions | Single source of truth for every `/api//...` URL the UI talks to. Each leaf is a function — `() => string` for constant paths, `(id, ...) => string` for parameterised ones. Wire-contract pinned by `src/api/endpoints.test.ts` (36 assertions). | ### `src/api/index.ts` (Public API barrel, since AZ-485 / F4) Re-exports the component's public surface: `api`, `createSSE`, `setToken`, `getToken`, `getApiBase`, `setNavigateToLogin`, `endpoints`. Consumers OUTSIDE this component MUST import from the barrel; direct imports of `src/api/{client,sse,endpoints}` from other components are blocked by `STC-ARCH-01`. ## 3. External API Specification This component does not *expose* an API; it consumes the suite's. The set of consumed endpoints (collected from feature module docs): | Service | Path prefix (after nginx strip) | Used by | |---------|---------------------------------|---------| | `admin/` auth | `/api/admin/auth/{login,refresh,logout,me,...}` | `02_auth`, `08_admin` | | `flights/` | `/api/flights/...` | `03_shared-ui` (FlightContext), `05_flights` | | `annotations/` | `/api/annotations/...` | `06_annotations`, `07_dataset`, `08_admin` (read) | | `detect/` | `/api/detect/...` | `06_annotations` | | `loader/`, `resource/`, `gps-denied-*`, `autopilot/` | `/api/{loader,resource,gps-denied-desktop,gps-denied-onboard,autopilot}/...` | various features | **No service-specific client modules exist**. URL strings are produced by typed builders in `src/api/endpoints.ts` (added by AZ-486 / F7, commit `8a461a2`) — the previous "URL strings inlined at every call site" testability finding (F7) is **CLOSED**. The `STC-ARCH-02` static gate (`scripts/check-arch-imports.mjs --mode=api-literals`, wired into `scripts/run-tests.sh`) forbids re-introducing `/api//...` literals under `src/`. ## 5. Implementation Details | Concern | Behavior | |---------|----------| | Auth bootstrap | `client.ts` does NOT auto-attach `credentials: 'include'` on the very first call from `AuthContext` startup — finding B3 (`src__auth__AuthContext.md`). Cookie-based session bootstrap therefore fails on first refresh. **PRIORITY for Step 4.** | | Refresh-token rotation | Server rotates access tokens via `X-Refresh-Token` header. `client.ts` handles refresh on 401 for fetch; `sse.ts` does **NOT** — `EventSource` holds the bearer captured at create time and dies after rotation (finding in `src__api__sse.md`). | | Timeouts | None — no `AbortController` wired up. Long requests (e.g., dataset bulk export) can hang indefinitely. Step 4. | | Error reporting | `ApiError` thrown to caller. Most features `catch` and call `alert()` or `console.error` silently — uneven across features. | **State Management**: Module-level only — `sse.ts` keeps no registry; each subscription is independent. **Key Dependencies**: native `fetch`, native `EventSource`. No third-party HTTP library. ## 7. Caveats & Edge Cases - **No timeout / cancellation**. (Step 4.) - **Bearer in SSE query string**. Accepted trade-off; document in `security_approach.md` (Step 6). - **No reconnect-on-token-rotate** for SSE consumers — every feature that uses SSE will silently stop receiving events after the first refresh (Step 8 hardening). - ~~No service-specific clients~~ → **CLOSED by AZ-486 / F7**: URL strings centralised in `src/api/endpoints.ts`; STC-ARCH-02 enforces it. Typos now surface at build time (TS strict on the builder names) or in `endpoints.test.ts`, never at runtime. ## 8. Dependency Graph **Must be implemented after**: `00_foundation`. **Can be implemented in parallel with**: `00_foundation` (it has no internal deps beyond types). **Blocks**: `02_auth`, every feature page, `03_shared-ui` (FlightContext, DetectionClasses). ## Module Inventory | Path | Module Doc | |------|------------| | `src/api/client.ts` | `_docs/02_document/modules/src__api__client.md` | | `src/api/sse.ts` | `_docs/02_document/modules/src__api__sse.md` | | `src/api/endpoints.ts` | `_docs/02_document/modules/src__api__endpoints.md` | | `src/api/index.ts` (barrel) | (no separate doc — re-exports surface listed in §2 above) |