T-iOS-1: ios/ XcodeGen project (iOS 17, Swift 6 strict concurrency, ATS per PLAN §5.2), 5 SPM package shells, CI skeleton T-iOS-2: Origin spike vs real server — URLSessionWebSocketTask custom Origin CONFIRMED (no Starscream); 16MiB replay + EMSGSIZE(40) errno correction written back to plan T-iOS-3: WireProtocol frozen contract, 59 tests, 100% line coverage, cross-impl vectors vs src/protocol.ts via tsx T-iOS-4: FakeTransport/FakeClock/FakeHTTPTransport doubles Verify: independent agent re-ran all acceptance — 6/6 PASS
31 lines
1.4 KiB
Swift
31 lines
1.4 KiB
Swift
/// The ONLY WS I/O boundary (frozen contract, plan §3.1/§3.2).
|
|
/// `URLSessionTermTransport` (SessionCore, T-iOS-9) and `FakeTransport`
|
|
/// (TestSupport, T-iOS-4) both implement this; `SessionEngine` cannot tell
|
|
/// them apart.
|
|
public protocol TermTransport: Sendable {
|
|
/// Open a WS connection to `endpoint.wsURL`, stamping
|
|
/// `Origin: endpoint.originHeader` on the upgrade (plan §5.1).
|
|
func connect(to endpoint: HostEndpoint) async throws -> TransportConnection
|
|
}
|
|
|
|
/// One live WS connection, as immutable capability handles (frozen contract).
|
|
public struct TransportConnection: Sendable {
|
|
/// Server JSON text frames, in arrival order. Stream finish = clean close;
|
|
/// stream throw = transport error (the two are distinguishable, T-iOS-9).
|
|
public let frames: AsyncThrowingStream<String, any Error>
|
|
/// Send one client JSON text frame (produced by `MessageCodec.encode`).
|
|
public let send: @Sendable (String) async throws -> Void
|
|
/// Close the connection (client detach — the server-side PTY keeps running).
|
|
public let close: @Sendable () async -> Void
|
|
|
|
public init(
|
|
frames: AsyncThrowingStream<String, any Error>,
|
|
send: @escaping @Sendable (String) async throws -> Void,
|
|
close: @escaping @Sendable () async -> Void
|
|
) {
|
|
self.frames = frames
|
|
self.send = send
|
|
self.close = close
|
|
}
|
|
}
|