- Notifications
You must be signed in to change notification settings - Fork11
Swift Package for Server-Side and Command-Line Access to CloudKit Web Services
License
brightdigit/MistKit
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A Swift Package for Server-Side and Command-Line Access to CloudKit Web Services
MistKit provides a modern Swift interface to CloudKit Web Services REST API, enabling cross-platform CloudKit access for server-side Swift applications, command-line tools, and platforms where the CloudKit framework isn't available.
Built with Swift concurrency (async/await) and designed for modern Swift applications, MistKit supports all three CloudKit authentication methods and provides type-safe access to CloudKit operations.
- 🌍 Cross-Platform Support: Works on macOS, iOS, tvOS, watchOS, visionOS, and Linux
- ⚡ Modern Swift: Built with Swift 6 concurrency features and structured error handling
- 🔐 Multiple Authentication Methods: API token, web authentication, and server-to-server authentication
- 🛡️ Type-Safe: Comprehensive type safety with Swift's type system
- 📋 OpenAPI-Based: Generated from CloudKit Web Services OpenAPI specification
- 🔒 Secure: Built-in security best practices and credential management
Add MistKit to yourPackage.swift file:
dependencies:[.package(url:"https://github.com/brightdigit/MistKit.git", from:"1.0.0-alpha.1")]
Or add it through Xcode:
- File → Add Package Dependencies
- Enter:
https://github.com/brightdigit/MistKit.git - Select version and add to your target
MistKit supports three authentication methods depending on your use case:
import MistKitletservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", apiToken:ProcessInfo.processInfo.environment["CLOUDKIT_API_TOKEN"]!)
letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", apiToken:ProcessInfo.processInfo.environment["CLOUDKIT_API_TOKEN"]!, webAuthToken: userWebAuthToken)
letserverManager=tryServerToServerAuthManager( keyIdentifier:ProcessInfo.processInfo.environment["CLOUDKIT_KEY_ID"]!, privateKeyData: privateKeyData)letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", tokenManager: serverManager, environment:.production, database:.public)
do{letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", apiToken:ProcessInfo.processInfo.environment["CLOUDKIT_API_TOKEN"]!) // Use service for CloudKit operations}catch{print("Failed to create service:\\(error)")}
Get API Token:
- Log intoApple Developer Console
- Navigate to CloudKit Database
- Generate an API Token
Set Environment Variable:
export CLOUDKIT_API_TOKEN="your_api_token_here"
Use in Code:
letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", apiToken:ProcessInfo.processInfo.environment["CLOUDKIT_API_TOKEN"]!)
Web authentication enables user-specific operations and requires both an API token and a web authentication token obtained through CloudKit JS authentication.
letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", apiToken: apiToken, webAuthToken: webAuthToken)
Server-to-server authentication provides enterprise-level access using ECDSA P-256 key signing. Note that this method only supports the public database.
Generate Key Pair:
# Generate private keyopenssl ecparam -genkey -name prime256v1 -noout -out private_key.pem# Extract public keyopenssl ec -in private_key.pem -pubout -out public_key.pem
Upload Public Key: Upload the public key to Apple Developer Console
Use in Code:
letprivateKeyData=tryData(contentsOf:URL(fileURLWithPath:"private_key.pem"))letserverManager=tryServerToServerAuthManager( keyIdentifier:"your_key_id", privateKeyData: privateKeyData)letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", tokenManager: serverManager, environment:.production, database:.public)
| Platform | Minimum Version | Server-to-Server Auth |
|---|---|---|
| macOS | 10.15+ | 11.0+ |
| iOS | 13.0+ | 14.0+ |
| tvOS | 13.0+ | 14.0+ |
| watchOS | 6.0+ | 7.0+ |
| visionOS | 1.0+ | 1.0+ |
| Linux | Ubuntu 18.04+ | ✅ |
| Windows | 10+ | ✅ |
MistKit provides comprehensive error handling with typed errors:
do{letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", apiToken: apiToken) // Perform operations}catchlet error asCloudKitError{print("CloudKit error:\\(error.localizedDescription)")}catchlet error asTokenManagerError{print("Authentication error:\\(error.localizedDescription)")}catch{print("Unexpected error:\\(error)")}
CloudKitError: CloudKit Web Services API errorsTokenManagerError: Authentication and credential errorsTokenStorageError: Token storage and persistence errors
Always store sensitive credentials in environment variables:
# .env file (never commit this!)CLOUDKIT_API_TOKEN=your_api_token_hereCLOUDKIT_KEY_ID=your_key_id_hereMistKit automatically masks sensitive information in logs:
// Sensitive data is automatically redacted in log outputprint("Token:\\(secureToken)") // Outputs: Token: abc12345***
For persistent applications, use secure token storage:
letstorage=InMemoryTokenStorage() // For development// Use KeychainTokenStorage() for production (implement as needed)lettokenManager=WebAuthTokenManager( apiToken: apiToken, webAuthToken: webAuthToken, storage: storage)letservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", tokenManager: tokenManager, environment:.development, database:.private)
For server-side applications, MistKit can useswift-openapi-async-http-client as the underlying HTTP transport. This is particularly useful for server-side Swift applications that need robust HTTP client capabilities.
import MistKitimport OpenAPIAsyncHTTPClient// Create an AsyncHTTPClient instancelethttpClient=HTTPClient(eventLoopGroupProvider:.createNew)// Create the transportlettransport=AsyncHTTPClientTransport(client: httpClient)// Use with CloudKit serviceletservice=tryCloudKitService( containerIdentifier:"iCloud.com.example.MyApp", apiToken: apiToken, transport: transport)// Don't forget to shutdown the client when donedefer{try? httpClient.syncShutdown()}
- Production Ready: AsyncHTTPClient is battle-tested in server environments
- Performance: Optimized for high-throughput server applications
- Configuration: Extensive configuration options for timeouts, connection pooling, and more
- Platform Support: Works across all supported platforms including Linux
For applications that might upgrade from API-only to web authentication:
letadaptiveManager=AdaptiveTokenManager( apiToken: apiToken, storage: storage)// Later, upgrade to web authenticationtryawait adaptiveManager.upgradeToWebAuth(webAuthToken: webToken)
Check out theExamples/ directory for complete working examples:
- Command Line Tool: Basic CloudKit operations from the command line
- Server Application: Using MistKit in a server-side Swift application
- Cross-Platform App: Shared CloudKit logic across multiple platforms
- API Documentation: Complete API reference
- DocC Documentation: Interactive documentation
- CloudKit Web Services: Apple's official CloudKit Web Services documentation
- Swift 6.1+
- Xcode 16.0+ (for iOS/macOS development)
- Linux: Ubuntu 18.04+ with Swift 6.1+
MistKit is released under the MIT License. SeeLICENSE for details.
- Built onSwift OpenAPI Generator
- UsesSwift Crypto for server-to-server authentication
- Inspired by CloudKit Web Services REST API
- Composing Web Service Requests ✅
- Modifying Records (records/modify) ✅
- Fetching Records Using a Query (records/query) ✅
- Fetching Records by Record Name (records/lookup) ✅
- Fetching Current User Identity (users/caller) ✅
- Vapor Token Client ✅
- Vapor Token Storage ✅
- Vapor URL Client ✅
- Swift NIO URL Client ✅
- Date Field Types ✅
- Location Field Types ✅
- System Field Integration ❌
- Name Component Types ❌
- Discovering User Identities (POST users/discover) ❌
- Discovering All User Identities (GET users/discover) ❌
- Support
postMessagefor Authentication Requests ❌ - Uploading Assets (assets/upload) ❌
- Referencing Existing Assets (assets/rereference) ❌
- Fetching Records Using a Query (records/query) w/ basic filtering ❌
- Handle Data Size Limits ❌
- Fetching Contacts (users/lookup/contacts) ❌
- Fetching Users by Email (users/lookup/email) ❌
- Fetching Users by Record Name (users/lookup/id) ❌
- Fetching Record Changes (records/changes) ❌
- Fetching Record Information (records/resolve) ❌
- Accepting Share Records (records/accept) ❌
- Fetching Zones (zones/list) ❌
- Fetching Zones by Identifier (zones/lookup) ❌
- Modifying Zones (zones/modify) ❌
- Fetching Database Changes (changes/database) ❌
- Fetching Record Zone Changes (changes/zone) ❌
- Fetching Zone Changes (zones/changes) ❌
- Fetching Subscriptions (subscriptions/list) ❌
- Fetching Subscriptions by Identifier (subscriptions/lookup) ❌
- Modifying Subscriptions (subscriptions/modify) ❌
- Creating APNs Tokens (tokens/create) ❌
- Registering Tokens (tokens/register) ❌
- Issues:GitHub Issues
- Discussions:GitHub Discussions
- Documentation:API Reference
MistKit: Bringing CloudKit to every Swift platform 🌟
About
Swift Package for Server-Side and Command-Line Access to CloudKit Web Services
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Contributors4
Uh oh!
There was an error while loading.Please reload this page.