Skip to main content

Documentation Index

Fetch the complete documentation index at: https://crsdk.app/llms.txt

Use this file to discover all available pages before exploring further.

AlphaSDK is the official Swift client for the Alpha Camera REST API. It uses URLSession only (zero third-party dependencies) and exposes Swift concurrency throughout.

Install

Add to your Package.swift dependencies:
.package(url: "https://github.com/jordlee/alpha-sdk-swift.git", from: "0.3.1"),
Then add AlphaSDK to your target’s dependencies:
.target(
    name: "MyApp",
    dependencies: [
        .product(name: "AlphaSDK", package: "alpha-sdk-swift"),
    ]
)
In Xcode: File → Add Package Dependencies…, paste the URL, choose from 0.3.1. You also need a server reachable from the device. The Swift client does not ship a ServerManager class — start the server using the Node-based CLI from the server package, or, on macOS, spawn the bundled binary from your application using Process (recipe). iOS applications typically connect over the local network to a server running on a Mac, Raspberry Pi, or similar host.

Initialize

import AlphaSDK

let client = AlphaSDKClient(baseURL: "http://localhost:8080")

Constructor options

let client = AlphaSDKClient(
    baseURL: "http://192.168.1.50:8080",      // base URL — defaults to localhost:8080
    headers: ["X-Trace-Id": "abc123"],         // applied to every request
    timeout: 30,                               // seconds
    maxRetries: 3,
    urlSession: .shared                        // bring your own URLSession
)
AlphaSDKClient is Sendable and safe to share across actors.

Common operations

List + connect a camera

let cameras = try await client.cameras.list()
guard let cameraId = cameras.cameras.first?.id else { return }

try await client.cameras.connect(
    cameraId: cameraId,
    request: .init(mode: .remoteTransfer, reconnecting: .on)
)

// Required for the host PC to drive most settings:
try await client.properties.setPriorityKey(
    cameraId: cameraId,
    request: .init(setting: .pcRemote)
)

Read a single property

let aperture = try await client.properties.get(
    cameraId: cameraId,
    propertyName: "aperture"
)
print(aperture.data.value, aperture.data.formatted)

Read every property at once

let res = try await client.properties.getAll(cameraId: cameraId)
for (name, entry) in res.data.properties {
    print(name, entry.currentFormatted, "writable=\(entry.writable)")
}
// `properties` is a [String: BulkPropertyEntry]; entries use the
// `current_*` field shape (NOT the same as single-property GET).

Set a property

try await client.properties.set(
    cameraId: cameraId,
    propertyName: "shutter-speed",
    request: .init(value: "1/250")
)

Trigger the shutter

// Single shot — pass an empty request body.
try await client.actions.shutter(cameraId: cameraId, request: .init())

// Continuous shooting (set drive mode to a continuous mode first):
try await client.actions.shutter(cameraId: cameraId, request: .init(action: .down))
// ... hold ...
try await client.actions.shutter(cameraId: cameraId, request: .init(action: .up))

Pull a single live-view JPEG

let data: Data = try await client.liveView.getFrame(cameraId: cameraId)
#if canImport(UIKit)
let image = UIImage(data: data)
#elseif canImport(AppKit)
let image = NSImage(data: data)
#endif
For OSD-overlaid frames after try await client.liveView.enableOsd(cameraId: cameraId):
let data = try await client.liveView.getOsdFrame(cameraId: cameraId)
See the live-view polling recipe for a render loop.

Disconnect

try await client.cameras.disconnect(cameraId: cameraId)

Error handling

Every method throws AlphaSDKError, an enum with cases for transport failures and HTTP responses. Pattern-match the case (or, for HTTP responses, classify with HTTPError.kind):
import AlphaSDK

do {
    try await client.properties.set(
        cameraId: cameraId,
        propertyName: "aperture",
        request: .init(value: "F1.0")  // not a valid value on this lens
    )
} catch let AlphaSDKError.httpError(http) {
    switch http.kind {
    case .validation, .client:
        print("server rejected the value (\(http.statusCode)):", http.body?.message ?? "")
    case .notFound:
        print("camera no longer connected")
    default:
        print("server error \(http.statusCode):", http.body?.message ?? "")
    }
} catch AlphaSDKError.timeout {
    print("request timed out")
} catch let AlphaSDKError.networkError(underlying) {
    print("network error:", underlying)
} catch {
    print("unexpected error:", error)
}
HTTPError exposes statusCode, parsed body (with message / code / type), and kind (.notFound, .validation, .client, .server, …). All other failure modes are dedicated cases on AlphaSDKError itself (.timeout, .networkError, .decodingError, …).

Advanced

Custom request headers per call

try await client.cameras.list(
    requestOptions: .init(additionalHeaders: ["X-Trace-Id": "request-42"])
)

Cancellation

Swift’s structured concurrency does the right thing — wrap the call in a Task and cancel:
let task = Task {
    try await client.properties.getAll(cameraId: cameraId)
}
// elsewhere:
task.cancel()

Bring your own URLSession

Useful for proxying, intercepting, or testing:
let config = URLSessionConfiguration.default
config.protocolClasses = [MyMockURLProtocol.self]
let urlSession = URLSession(configuration: config)

let client = AlphaSDKClient(
    baseURL: "http://localhost:8080",
    urlSession: urlSession
)

What’s NOT in the client

By design, the following live in recipes rather than the generated SDK:

Versioning

AlphaSDK follows SemVer. Every release is git-tagged on the SwiftPM repository — see the CHANGELOG there for release notes.