learning_ai_common_plat/packages/swift-platform-sdk/README.md
saravanakumardb1 55a1256d8b docs(swift,kotlin): Add comprehensive SDK READMEs with broadcast and survey examples
- Swift SDK README: Installation, Broadcast/Survey clients, SwiftUI integration, push notifications
- Kotlin SDK README: Gradle setup, Jetpack Compose components, FCM integration
2026-03-03 08:30:26 -08:00

216 lines
9.4 KiB
Markdown

# ByteLystPlatformSDK
Shared Swift platform client for all ByteLyst iOS/watchOS/macOS apps. Eliminates code duplication across products by providing a single source of truth for platform-service integration.
## What's Inside
| File | What It Does |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `BLPlatformConfig` | Product-specific configuration (productId, baseURL, bundleId, appGroupId) |
| `BLPlatformClient` | Generic HTTP client with auth injection, x-request-id, timeout |
| `BLKeychain` | Keychain CRUD for secure token storage |
| `BLTelemetryClient` | Telemetry event queue + batch flush (matches `@bytelyst/telemetry-client`) |
| `BLAuthClient` | Auth operations: login, register, refresh, password ops, email verify, delete account (matches `@bytelyst/auth-client`) |
| `BLFeatureFlagClient` | Feature flag polling from platform-service `/api/flags/poll` |
| `BLSyncEngine` | Generic offline-first sync engine with delta pull + batch push |
| `BLBlobClient` | Azure Blob Storage upload via SAS tokens from platform-service |
| `BLKillSwitchClient` | Kill switch check from platform-service (fail-open) |
| `BLLicenseClient` | License key activation + status via platform-service |
| `BLBiometricAuth` | Face ID / Touch ID wrapper (LocalAuthentication) |
| `BLCrashReporter` | MetricKit crash and hang reporting with local storage |
| `BLAuditLogger` | Local rotating JSON audit log for debugging |
## Usage
### 1. Add to Xcode Project
In Xcode: **File → Add Package Dependencies → Add Local...** → select this directory:
```
../learning_ai_common_plat/packages/swift-platform-sdk/
```
Or in `Package.swift`:
```swift
.package(path: "../learning_ai_common_plat/packages/swift-platform-sdk")
```
### 2. Configure at App Launch
```swift
import ByteLystPlatformSDK
// Create config — one per app
let config = BLPlatformConfig.fromInfoPlist(
productId: "peakpulse",
defaultBaseURL: "https://api.peakpulse.app",
bundleId: "com.saravana.peakpulse"
)
// Create shared HTTP client
let client = BLPlatformClient(config: config)
// Create services
let telemetry = BLTelemetryClient(config: config, client: client)
let auth = BLAuthClient(config: config, client: client)
let flags = BLFeatureFlagClient(config: config, client: client)
```
### 3. Telemetry
```swift
telemetry.start()
telemetry.trackEvent("info", module: "session", name: "session_started", metrics: ["elevation": 2450.0])
telemetry.trackScreen("live_tracking")
// On app background:
telemetry.stop()
```
### 4. Auth
```swift
// Login
let user = try await auth.login(email: "user@example.com", password: "secret")
// Restore on launch
await auth.restoreSession()
// Listen for state changes
auth.onAuthStateChanged = { state in
switch state {
case .loggedIn(let user): print("Hello, \(user.displayName)")
case .loggedOut: print("Signed out")
case .error(let msg): print("Auth error: \(msg)")
case .loading: print("Loading...")
}
}
```
### 5. Feature Flags
```swift
flags.start(userId: auth.accessToken != nil ? "user-id" : nil)
if flags.isEnabled("peakpulse.pro_charts") {
// Show Pro charts
}
```
### 6. Sync Engine
```swift
// Implement your product-specific adapter
struct PeakSessionSyncAdapter: BLSyncAdapter {
typealias SyncItem = PeakSessionDTO
func pullDelta(since: Date?, client: BLPlatformClient) async throws -> [PeakSessionDTO] {
var path = "/api/peak-sessions/sync"
if let since { path += "?since=\(ISO8601DateFormatter().string(from: since))" }
return try await client.request(path: path, responseType: [PeakSessionDTO].self)
}
func pushBatch(_ items: [BLOfflineQueueItem], client: BLPlatformClient) async throws -> BLBatchResult {
let body = try JSONEncoder().encode(["items": items.compactMap(\.payload)])
let (data, _) = try await client.rawRequest(path: "/api/peak-sessions/batch", method: "POST", body: body)
return try JSONDecoder().decode(BLBatchResult.self, from: data)
}
}
let syncEngine = BLSyncEngine(
config: config,
client: client,
adapter: PeakSessionSyncAdapter()
)
```
## Product Apps Using This SDK
| Product | Repo | Wrappers | Status |
| ---------- | ----------------------------------- | -------- | ----------------------------------- |
| ChronoMind | `learning_ai_clock` | 5 files | ✅ Migrated (Cloud/ + Diagnostics/) |
| LysnrAI | `learning_voice_ai_agent` | 9 files | ✅ Migrated (Auth/ + Util/) |
| MindLyst | `learning_multimodal_memory_agents` | 4 files | ✅ Migrated (Services/) |
| PeakPulse | `learning_ai_peakpulse` | — | New — will use SDK from day one |
| NomGap | `learning_ai_fastgap` | — | React Native — uses TS packages |
## What This Replaces
Before this SDK, each iOS app had its own copy of platform integration code:
| ChronoMind (old) | LysnrAI (old) | MindLyst (old) | SDK (new) |
| --------------------------------- | ------------------------------- | ------------------------------- | --------------------- |
| `KeychainHelper` (53 lines) | `KeychainHelper` (60 lines) | `KeychainHelper` (60 lines) | `BLKeychain` |
| `CMTelemetryService` (139 lines) | `TelemetryService` (288 lines) | `TelemetryService` (139 lines) | `BLTelemetryClient` |
| `CMAuthService` (359 lines) | `AuthService` (421 lines) | `AuthService` (389 lines) | `BLAuthClient` |
| `FeatureFlagService` (72 lines) | `FeatureFlagService` (71 lines) | `FeatureFlagService` (72 lines) | `BLFeatureFlagClient` |
| `CrashReporter` (153 lines) | — | — | `BLCrashReporter` |
| — | `BlobService` (118 lines) | — | `BLBlobClient` |
| — | `KillSwitchService` (48 lines) | — | `BLKillSwitchClient` |
| — | `LicenseService` (135 lines) | — | `BLLicenseClient` |
| — | `BiometricAuth` (65 lines) | — | `BLBiometricAuth` |
| — | `AuditLogger` (70 lines) | — | `BLAuditLogger` |
| `PlatformSyncManager` (450 lines) | Various sync files | — | `BLSyncEngine` |
Total duplicated code eliminated: **~2,600+ lines across 3 product apps**.
## Design Decisions
1. **No `@MainActor`** — the SDK is thread-safe via NSLock. Product apps can wrap in `@MainActor` at the view model layer.
2. **No singletons** — product apps own the lifecycle. Create instances at app launch, inject where needed.
3. **No SwiftUI dependency** — pure Foundation. Works in watchOS, macOS, widgets, extensions.
4. **Protocol-based sync**`BLSyncAdapter` lets each product define its own DTOs and endpoints while reusing the queue/timer/conflict plumbing.
5. **Fire-and-forget telemetry** — errors never surface to the user. Matches the TypeScript package behavior.
## Platforms
- iOS 17+
- watchOS 10+
- macOS 14+
## Broadcast & Survey
New in v1.2: In-app messaging and survey capabilities.
### Broadcast Client
```swift
import ByteLystPlatformSDK
let config = BLPlatformConfig(
productId: "lysnrai",
baseURL: URL(string: "https://api.bytelyst.io/v1")!,
getAuthToken: { await getToken() }
)
let broadcastClient = BLBroadcastClient(config: config)
// Start polling for messages
broadcastClient.startPolling(intervalMs: 60000) { messages in
// Handle new messages
}
// SwiftUI UI components
BLInAppMessageBanner(client: broadcastClient, position: .top)
BLBroadcastModal(client: broadcastClient)
```
### Survey Client
```swift
let surveyClient = BLSurveyClient(config: config)
// Check for active surveys
let (survey, _) = await surveyClient.getActiveSurvey()
// Start and complete survey
await surveyClient.startSurvey(surveyId: survey.id)
await surveyClient.submitAnswer(surveyId: survey.id, questionId: "q1", answer: answer)
await surveyClient.completeSurvey(surveyId: survey.id)
// SwiftUI modal
BLSurveyModal(client: surveyClient)
```
See [Broadcast & Survey Guide](BROADCAST_SURVEY_GUIDE.md) for full documentation.