cocottetech/@platform/codebase/@features/ai-copilot/cockpit-kit/Sources/CocotteCockpitKit/CockpitAPI.swift
Natalie d114d9d375 feat(cockpit-kit): 📸 add bump screenshot overlay
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-10 05:00:56 -07:00

67 lines
4 KiB
Swift

import Foundation
// The data seam. CockpitModel loads through CockpitAPI, so the UI is source-
// agnostic: MockCockpitAPI now, LiveCockpitAPI ( platform-api on black:3060)
// when the engine is up. Pattern mirrors v2's MessagingAPIClient.
public protocol CockpitAPI: Sendable {
func fetchDrops() async throws -> [ContentDrop]
func fetchPending() async throws -> [PendingApproval]
func fetchAssets() async throws -> [Asset]
func fetchActions() async throws -> [AgentAction]
func fetchSpecialists() async throws -> [Specialist]
func fetchMetrics() async throws -> [SurfaceMetric]
func fetchIngestStatus() async throws -> IngestStatus
func controlIngestion(_ action: IngestControlAction) async throws -> IngestStatus
func approve(_ approvalId: UUID, edited: Bool) async throws
func setAside(_ approvalId: UUID) async throws
/// Persist a composed drop (title + arc + scheduled time) and link the selected
/// assets. Returns the created drop as a Kit model so the optimistic row can be
/// reconciled with the server's. Legs are not part of create they fan out
/// separately (live drops carry no legs in the cockpit today).
func createDrop(title: String, arc: String, assetIds: [UUID], dropAt: Date) async throws -> ContentDrop
/// Best-effort fetch of an asset's image bytes (authenticated proxy). Returns
/// nil when the asset has no backing media (mock/composed) or the fetch fails
/// the tile falls back to its placeholder swatch, never errors.
func fetchImageData(for asset: Asset) async -> Data?
/// Best-effort fetch of the newest availability-bump overlay screenshot for a
/// surface (authenticated proxy). Returns nil when none has been captured yet
/// or the fetch fails the card simply doesn't render, never errors.
func fetchBumpScreenshot(surface: String) async -> Data?
}
public enum CockpitAPIError: Error, Sendable {
// Endpoint not yet on platform.api. Transport/HTTP/decoding failures surface
// as CocottePlatformAPIClient.APIError from the shared client.
case unavailable(String)
}
// Local / demo source returns the mock dataset; approve/set-aside are no-ops (the
// model mutates its own state optimistically). `createDrop` echoes the composed drop
// back so the live reconcile path is exercised against the mock too.
public struct MockCockpitAPI: CockpitAPI {
public init() {}
public func fetchDrops() async throws -> [ContentDrop] { Mock.drops }
public func fetchPending() async throws -> [PendingApproval] { Mock.pending }
public func fetchAssets() async throws -> [Asset] { Mock.assets }
public func fetchActions() async throws -> [AgentAction] { Mock.actions }
public func fetchSpecialists() async throws -> [Specialist] { Mock.specialists }
public func fetchMetrics() async throws -> [SurfaceMetric] { Mock.metrics }
public func fetchIngestStatus() async throws -> IngestStatus {
IngestStatus(enabled: true, state: .running, totalPhotos: 11_123, processed: 4_200,
hotCount: 380, stockedCount: 3_820, explicitCount: 1_290, failedCount: 12)
}
public func controlIngestion(_ action: IngestControlAction) async throws -> IngestStatus {
try await fetchIngestStatus()
}
public func approve(_ approvalId: UUID, edited: Bool) async throws {}
public func setAside(_ approvalId: UUID) async throws {}
public func createDrop(title: String, arc: String, assetIds: [UUID], dropAt: Date) async throws -> ContentDrop {
ContentDrop(title: title, arc: arc, assetCount: assetIds.count, clusterSource: "composed",
legs: [], teaseAt: nil, dropAt: dropAt, followupAt: nil, state: .scheduled)
}
// No real media in the demo dataset tiles render their placeholder swatch.
public func fetchImageData(for asset: Asset) async -> Data? { nil }
// No live browser in the demo the bump screenshot card stays hidden.
public func fetchBumpScreenshot(surface: String) async -> Data? { nil }
}