weishu
|
15f48c9c65
|
feat(ios): SSE client + reconnect state machine (A-M1c)
HapiClient/SSE per docs/api/client-contract/sse.md and the web reference
(web/src/hooks/useSSE.ts):
- SSELineParser: incremental frame parser (LF/CRLF, multi-line data,
comments, retry ignored); per-block ids only — sticky-cursor semantics
live in the caller so id-less heartbeats can never blank the cursor.
- ReconnectPolicy + SSETimings: 0s first retry, 1s x2 capped at 30s,
300s slow ceiling after 8 attempts, 0-500ms injectable jitter; connect
timeout 10s, staleness 90s, foreground-resume 45s, watchdog tick 10s.
- SSETransport protocol + URLSessionSSETransport (URLSession.bytes with
dedicated config: 300s idle timeout, 7d resource, no waitsForConnectivity).
- actor SSEClient: idle/connecting/connected/backoff/suspended machine;
handshake-gated connected state surfacing resume ok|gap; per-subscription
cursor sent as ?lastEventId, advanced only after consumer yield
(at-least-once); one free token-refresh retry per connect cycle on 401;
suspend defers retries, resume applies the 45s staleness check;
acceptEncodingIdentity escape hatch (gzip streaming verification TODO).
- NetworkPathObserving + NWPathObserver: path change while connected is
treated as a transport error (immediate reconnect).
- swift-testing suite on a fake transport + manual clock: parser edge
cases, exact backoff schedule + seeded jitter bounds, handshake gating,
ok/gap verdicts, cursor replay + isolation, heartbeat vs watchdog,
90s staleness, connect timeout, suspend/resume, event ordering,
unknown-type passthrough, 401 bypass cap, path-change reconnect.
|
2026-08-17 15:28:14 +08:00 |
|
weishu
|
1f0ec6184d
|
feat(ios): HapiClient API transport + auth (A-M1b)
APIClient (final class, Sendable) with typed endpoints for the M2/M3 REST
surface behind an HTTPPerforming seam; actor AuthManager with single-flight
JWT refresh (POST /api/auth), proactive refresh 10 min before exp, terminal
authFailed state, and 401 -> refresh -> retry-once wiring per
docs/api/client-contract/auth.md; Keychain credential store (per-hub records
under run.hapi.companion) with CredentialStoring seam + in-memory double;
HubRegistry (ordered hubs + active hub in injectable UserDefaults, origin
normalization); payload-only JWT decoding; APIError {status, code, body}
parsing per errors.md; minimal multipart builder for M4c dictation; 256 MB
URLCache session for generated images.
Request/response wire models (SendMessageRequest, PermissionApproveRequest,
SpawnRequest/SpawnResponse, MessagesQuery, envelopes, RPC-wrapped shapes)
join HapiProtocol/Models mirroring shared/src/apiTypes.ts.
swift-testing coverage: JWT decode (padding/garbage/hostile exp), auth
single-flight (8 concurrent callers -> one exchange), 401 retry-once and
terminal paths, APIError body parsing, endpoint request construction
byte-checks (cursor queries, deliveryMode body, answers formats, explicit
null model reset) via a recording performer, hub URL normalization,
multipart bytes.
|
2026-08-17 15:20:03 +08:00 |
|