When to use
- Desktop apps (Electron, Tauri, PyQt, SwiftUI macOS) that should be self-contained — the user shouldn’t have to start a separate server
- CI or test environments that need a camera server per run
- Dev harnesses where you’re iterating on server + client together
When NOT to use
- Anything on iOS — iOS apps can’t spawn subprocesses. Use a server running elsewhere (laptop, Raspberry Pi).
- Browser-only UIs — point at an already-running server
- Server is deployed separately from your app (e.g. always-on Pi)
Where does the binary come from?
The camera server binary ships with@alpha-sdk/api on npm via platform-specific optional dependencies. For self-contained apps, the easiest path:
- Node/Electron:
npm install @alpha-sdk/api— thecamera-serverCLI innode_modules/.bin/is the binary launcher - Python: Install Node +
@alpha-sdk/api, or download the binary from GitHub releases - Swift macOS: Ship the binary inside your
.appbundle’s Resources, or download on first run
node_modules/@alpha-sdk/darwin-arm64/CameraWebApp), then falls back to CAMERA_SERVER_BINARY.
TypeScript / Node.js
Complete recipe
Usage
- route owns
ServerManager - browser code only talks to
/api/server - the camera lifecycle layer then points
@alpha-sdk/clientat the returned port
Python
Complete recipe
Usage
Swift (macOS only)
iOS cannot spawn processes. This recipe applies only to macOS (#if os(macOS)).
Complete recipe
Usage
Common pitfalls
- Handle Ctrl-C. If your app gets SIGINT, you need to call
stop()— otherwise the server keeps running. Wire a signal handler or use the context-manager variants (Pythonasync with, Swiftdefer). - Port conflicts. The real macOS app does not assume 8080 is free. It first reuses a healthy server, then reaps stale
CameraWebApporphans, then walks to the next free port. - Stdout buffering. Node’s
spawndoesn’t buffer if you drainstdout. Python needsbufsize=1+ explicit read loop. Swift needs areadabilityHandler. Forgetting these silently stalls the server when its output buffer fills (~64KB). - Don’t kill the server on minor errors. Only call
stop()on app exit or when you actually want it gone. Transient HTTP errors from camera commands aren’t server problems. - Main-actor teardown can deadlock on app quit. The real app snapshots
serverURL+connectedCameraIdand performs shutdown with plainURLSessionoff-actor so AppKit termination does not hang.
Health check before starting
If you want to avoid a port conflict, probe first:Verified against
The Swift section mirrorsexample_swift_app/Sources/AlphaCameraExample/ServerManager.swift and its shutdown path in example_swift_app/Sources/AlphaCameraExample/AppCoordinator.swift.
