New SDK components extracted from product apps: - BLBlobClient — Azure Blob Storage upload via SAS tokens (from LysnrAI BlobService) - BLKillSwitchClient — Kill switch check from platform-service (from LysnrAI KillSwitchService) - BLLicenseClient — License key activation + status (from LysnrAI LicenseService) - BLBiometricAuth — Face ID / Touch ID wrapper (from LysnrAI BiometricAuth) - BLCrashReporter — MetricKit crash reporting (from ChronoMind CrashReporter) - BLAuditLogger — Local rotating JSON audit log (from LysnrAI AuditLogger) SDK now has 13 source files. Updated README with full component table and migration status (3 apps fully migrated, 18 wrappers total).
169 lines
8.3 KiB
Markdown
169 lines
8.3 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 `/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+
|