mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-08 19:19:42 +00:00
ios/scripts/linux-test.sh stages HapiKit + shared/fixtures at repo depth
into a persistent tmp dir and runs swift test in swift:6.1-noble; the
manifest drops HapiUI (SwiftUI/swift-markdown/Highlightr) under
#if os(Linux). 458 tests green, including all 48 chat and 11 pagination
golden fixtures.
Fixes that fell out of the first real compile of the blind-written port:
- ChatTypes.CodexReview.wireValue + SummaryPatching legacy id fallback:
split expressions that exceeded the Swift 6 type-checker budget
- FileEndpointsTests: raw string containing "# terminated the literal
early (never compiled anywhere) — now ##-delimited
- SSEClient.backoffSleep: Task { try? ... } inferred Task<()?, Never>
- Darwin gates: Security/Keychain behind canImport(Security) (tests use
InMemoryCredentialStore via CredentialStoring), CryptoKit digest with
FNV-1a filename fallback, FoundationNetworking imports for URLSession
types, corelibs URLCache diskPath: initializer, get-only
waitsForConnectivity, delegate-based SSE transport where
URLSession.bytes(for:) does not exist
59 lines
2.2 KiB
Swift
59 lines
2.2 KiB
Swift
import Foundation
|
|
#if canImport(FoundationNetworking)
|
|
import FoundationNetworking // URLSession types live here on Linux
|
|
#endif
|
|
import HapiProtocol
|
|
|
|
/// Generated images and message-attachment uploads
|
|
/// (`docs/api/client-contract/rest.md`).
|
|
extension APIClient {
|
|
/// `GET /api/sessions/:id/generated-images/:imageId` — raw bytes.
|
|
///
|
|
/// The image id is a content fingerprint doubling as the `ETag`, and the
|
|
/// hub sends `Cache-Control: private, max-age=31536000, immutable`, so
|
|
/// the configured `URLCache` (see ``URLSessionHTTPPerformer``) serves
|
|
/// repeats locally and revalidates with `If-None-Match` transparently.
|
|
public func generatedImage(
|
|
sessionId: String,
|
|
imageId: String
|
|
) async throws -> (data: Data, mimeType: String?) {
|
|
let (data, response) = try await requestBytes(
|
|
"/api/sessions/\(encodePathComponent(sessionId))/generated-images/\(encodePathComponent(imageId))"
|
|
)
|
|
return (data, response.value(forHTTPHeaderField: "Content-Type"))
|
|
}
|
|
|
|
/// `POST /api/sessions/:id/upload` — JSON + base64, **not** multipart.
|
|
/// Decoded size limit 50 MB (413 above). Requires an active session.
|
|
/// Pass the returned `path` in the `attachments` metadata of a
|
|
/// subsequent send-message.
|
|
public func uploadFile(
|
|
sessionId: String,
|
|
filename: String,
|
|
data: Data,
|
|
mimeType: String
|
|
) async throws -> UploadFileResponse {
|
|
try await request(
|
|
.post,
|
|
"/api/sessions/\(encodePathComponent(sessionId))/upload",
|
|
body: UploadFileRequest(
|
|
filename: filename,
|
|
content: data.base64EncodedString(),
|
|
mimeType: mimeType
|
|
)
|
|
)
|
|
}
|
|
|
|
/// `POST /api/sessions/:id/upload/delete` — removes a pending upload.
|
|
public func deleteUpload(sessionId: String, path: String) async throws -> DeleteUploadResponse {
|
|
struct DeleteUploadRequest: Encodable {
|
|
let path: String
|
|
}
|
|
return try await request(
|
|
.post,
|
|
"/api/sessions/\(encodePathComponent(sessionId))/upload/delete",
|
|
body: DeleteUploadRequest(path: path)
|
|
)
|
|
}
|
|
}
|