ShipinKit is an unofficial Swift SDK for prototyping typed video-generation flows with the Runway and Luma APIs.
- Typed, provider-specific requests and responses; no public
Anyreturn values - A lazily resolved, always-redacted
ShipinCredential - An injectable
ShipinTransportfor deterministic tests and app-owned networking - Runway API version
2024年11月06日with Gen-4.5 and Gen-4 Turbo contracts - Luma Ray 2 and Ray 2 Flash video-generation contracts
- Structured task states, failure receipts, polling timeouts, and cancellation handling
- Finite per-request timeouts and path-safe provider identifiers
- Offline fixture tests that never require or call a live provider account
ShipinKit never logs credentials, authorization headers, prompt bodies, or provider responses.
- Swift 6.0+
- iOS 16+, macOS 14+, tvOS 16+, watchOS 9+, or visionOS 1+
dependencies: [ .package(url: "https://github.com/rryam/ShipinKit.git", from: "2.0.0") ]
Then add ShipinKit to your target dependencies.
Do not commit API keys or put them in a shared Xcode scheme. Resolve them from an app-owned secrets service instead:
let credential = ShipinCredential { try await secrets.runwayAPIKey() }
The closure is called at request time, so an application can rotate a credential without recreating its client. String(describing:) and String(reflecting:) always produce <redacted>.
An API key embedded in a distributed client app cannot be kept fully secret. For production apps, keep provider credentials on a server you control and expose a narrow authenticated endpoint to the app. Direct provider access is best limited to local tools and prototypes.
Create a typed request, start it, and wait for the complete task receipt:
import ShipinKit let image = try RunwayMLImageSource( url: URL(string: "https://example.com/input.jpg")! ) let request = try RunwayMLImageToVideoRequest( model: .gen4Turbo, promptImage: image, promptText: "A slow camera push through morning fog", duration: .fiveSeconds, ratio: .landscape ) let runway = RunwayML(credential: credential) let result = try await runway.generateVideo(request) switch result.task.state { case .succeeded(let output): // Store provider output promptly; provider URLs are temporary. use(output) default: break }
For manual task control:
let created = try await runway.createImageToVideoTask(request) let latest = try await runway.task(id: created.id) try await runway.cancelOrDeleteTask(id: created.id)
The request type deliberately supports the shared Gen-4.5 and Gen-4 Turbo image-to-video fields. Other Runway models have different parameter contracts and are not represented as if they were interchangeable.
import ShipinKit let credential = ShipinCredential { try await secrets.lumaAPIKey() } let request = try LumaAIGenerationRequest( prompt: "A paper boat moving across a calm pond", model: .ray2, resolution: .p720, duration: .fiveSeconds, aspectRatio: .landscape ) let luma = LumaAI(credential: credential) let result = try await luma.generateVideo(request) use(result.videoURL)
Image-to-video uses typed keyframes:
let keyframes = try LumaAIKeyframes( frame0: .image(URL(string: "https://example.com/start.jpg")!) ) let request = try LumaAIGenerationRequest( prompt: "A tiger walks forward through falling snow", keyframes: keyframes )
Current Luma camera concepts are typed in requests and discoverable from the provider:
let concept = try LumaAIConcept(key: "dolly_zoom") let request = try LumaAIGenerationRequest( prompt: "A car on a mountain road", concepts: [concept] ) let availableConcepts = try await luma.listConcepts()
Known resolution and duration cases have named values. Their .custom(...) cases preserve newer provider values without requiring a ShipinKit release first.
If the application chooses a provider dynamically, ShipinClient returns a typed enum:
let client = ShipinClient( service: .runwayML(credential: credential) ) switch try await client.generate(.runwayML(request)) { case .runwayML(let task): use(task.id) case .lumaAI: break }
All clients accept any ShipinTransport. Tests can return fixture data and inspect the generated URLRequest without making a network call:
struct FixtureTransport: ShipinTransport { let response: ShipinHTTPResponse func send(_ request: URLRequest) async throws -> ShipinHTTPResponse { response } }
Each client also accepts a requestTimeout (60 seconds by default). Polling has a separate overall timeout, so one stalled request and one long-running generation have independent limits.
- Import and link the
ShipinKitproduct. The published1.0.0product was namedRunveyKit. - Replace the old multi-parameter
generate(...) -> Anycall with aLumaAIGenerationRequestorRunwayMLImageToVideoRequest. - Replace
gen3a_turbo,16:9/9:16Runway values, and the old version header with the typed current model, resolution, and duration values. - Remove the obsolete Runway
watermarkparameter; it is not part of the current image-to-video contract. - Handle
ShipinErrorfor validation, transport, HTTP, terminal generation, and timeout failures. - Replace live placeholder tests with an injected
ShipinTransportand fixture responses.
Provider contracts are based on the official Runway API reference, Runway model catalog, and Luma video-generation documentation.
ShipinKit is available under the MIT license. It is not affiliated with or endorsed by Runway or Luma AI.