# Shade V3.7 — Transport Bridge (SSE / long-poll)

**Status:** Implementert
**Effort:** M (2–4 uker)
**Forrige:** V3.6
**Adresserer:** V2.3 §3
**Leveranse:** `@shade/transport-bridge` 0.1.0 + `createBridgeRoutes` i
`@shade/inbox-server`. Brukerveiledning: [`docs/transport.md`](../transport.md).

---

## Mål

Apper som ikke kan eller vil bruke WebSocket — strenge proxies,
browser-extensions, edge-environments — får **ferdig pattern** for å ta imot
små meldinger og kontroll-signaler. SSE som primær fallback, long-poll som
sekundær.

---

## Scope

### Inn

- `@shade/transport-bridge` — ny submodul i `@shade/transport` (eller egen
  pakke).
- SSE-endpoint i `@shade/server` (kombineres med inbox fra V3.6 for "hent
  fra inbox uten plaintext").
- Long-poll fallback med konfigurerbar timeout.
- Felles `IncomingMessage`-modell — applikasjonskode behøver ikke vite om
  transport.
- Auto-fallback: WS → SSE → long-poll (samme mønster som transfer-transport).

### Ut

- HTTP/2 push.
- WebTransport — browser-støtte fortsatt umoden i 2026.

---

## Design

### Felles type

```ts
interface IncomingMessage {
  from: string;
  bytes: Uint8Array;
  receivedAt: number;
}

interface BridgeTransport {
  connect(opts: { onMessage(msg: IncomingMessage): void }): Promise<void>;
  disconnect(): Promise<void>;
}
```

### SSE

- Endpoint: `GET /v1/bridge/stream` med `Last-Event-ID` for cursor-resume.
- Server-side: emitterer `envelope-ready`-event når inbox får ny.
- Klient åpner én EventSource; reconnect på drop.

### Long-poll

- Endpoint: `GET /v1/bridge/poll?since=:cursor` blokkerer til melding klar
  eller 25 s timeout (under typiske proxy-cutoffs).
- Klient repeterer.

### Fallback

- `FallbackBridgeTransport([WsBridge, SseBridge, LongPollBridge])` prøver i
  rekkefølge.

---

## Leveranser

### Kode

- `@shade/transport-bridge` med `WsBridge`, `SseBridge`, `LongPollBridge`,
  `FallbackBridgeTransport`.
- Server: SSE og long-poll routes på `@shade/server` eller
  `@shade/inbox-server`.

### Tester

- Unit: hver bridge åpner/lukker korrekt; reconnect på drop.
- Integration: WS down → faller til SSE; SSE 502 → long-poll.
- Same `IncomingMessage` shape ut fra alle tre.

### Dokumentasjon

- `docs/transport.md` utvidet med bridge-oversikt.

---

## Akseptansekriterier

- [x] Samme test-suite "send 100 small messages" passer på alle tre
      transports.
- [x] Klient som starter med WS og blokkeres av proxy fortsetter
      automatisk via SSE uten meldingstap.
- [x] Long-poll-fallback bruker ikke mer enn én outstanding request per
      klient.

---

## Avhengigheter

- V3.6 — naturlig komplement; SSE-payload er typisk "envelope er klar i
  inbox".

---

## Risiko

- **Reconnect-cykluser.** SSE som flapper kan tape meldinger. Mitiger med
  Last-Event-ID + at server beholder kort buffer.
- **Long-poll keepalive.** Proxy-timeouts kan kutte før 30 s; juster
  default til 25 s.

---

## Migrasjon

Additivt.
