<!-- source-hash: 585108e1683f75548fc4f177781fa0c8 -->
A client-side `fetch` wrapper for embedded surfaces (chat, ticket center, widgets) that automatically attaches bearer-act-as proxy authentication headers from `sessionStorage` while enforcing same-origin security.

## Key Components

### `embedAuthedFetch(url, init?)`
Drop-in replacement for `fetch()` that:
- Normalizes `RequestInit.headers` (handles `Headers` instance, tuple arrays, or plain objects) into `Record<string, string>`
- Delegates to `applyProxyAuth` to merge `Authorization` and `X-Chat-Act-As` headers — **proxy credentials always win** over caller-supplied headers
- Defaults `Content-Type: application/json` when no headers are provided
- Forces `credentials: 'same-origin'` to ensure Supabase auth cookies are included alongside bearer tokens
- **Self-heals on `401`** when a host registered an `EmbedAuthAdapter` with a `refresh` callback: calls `refresh()` once, and on success retries the same request a single time with freshly-recomputed headers (so a rotated bearer is picked up). Concurrent 401s share ONE refresh. With no adapter / no `refresh`, the 401 passes through unchanged.

### `setEmbedAuthAdapter(adapter | null)` + `EmbedAuthAdapter`
Optional host-owned auth override registered at module level (one chat panel per app). The adapter can supply:
- `getHeaders()` — headers merged onto every call AFTER proxy-auth (adapter wins), re-read per request so token rotation is seen
- `credentials` — overrides the default `'same-origin'` (e.g. `'include'` for cross-origin cookie auth)
- `refresh()` — `Promise<boolean>` 401 self-heal hook (see above). This lifts the openframe `apiClient`'s refresh-then-retry behaviour into the lib so embedded surfaces no longer need a host-side `window.fetch` monkey-patch to survive an expired token mid-session.

### `assertSameOrigin(url)` *(internal)*
Defense-in-depth guard that:
- Resolves all URL forms (relative, absolute, protocol-relative, whitespace-prefixed) against `window.location.href` via the WHATWG `URL` constructor — bypasses regex shortcuts vulnerable to `\t`/`\n` prefix tricks
- Blocks non-`http(s):` schemes explicitly (`javascript:`, `data:`, `blob:`, etc.)
- Throws on cross-origin destinations before any bearer token leaves the page
- Skips silently during SSR (`typeof window === 'undefined'`)

## Usage Example

```typescript
// JSON POST to chat API — proxy headers attached automatically
const res = await embedAuthedFetch('/api/chat/messages', {
  method: 'POST',
  body: JSON.stringify({ message: 'Hello' }),
})

// GET with explicit empty headers — skips Content-Type default
const upload = await embedAuthedFetch('/api/storage/generate-upload-url', {
  method: 'GET',
  headers: {},
})

// Vanilla fetch — use for routes that don't need bearer-act-as
const profile = await fetch('/api/profile/me', { credentials: 'same-origin' })
```

> Routes outside the `/api/chat/*`, `/api/docs/chat/*`, or `/api/storage/generate-upload-url` surfaces should use vanilla `fetch` — this wrapper is scoped to embedded auth contexts only.