Skip to content

Validation & revalidation

checkOnLaunch() runs once at startup. For apps that stay open for days (menu bar utilities, dev tools, IDE plugins), a revoked or expired license can go undetected until the next cold start. The manager provides two safety nets.

Call manager.refreshIfNeeded() from .onChange(of: scenePhase) when the app becomes .active:

.onChange(of: scenePhase) { phase in
if phase == .active {
Task { await manager.refreshIfNeeded() }
}
}

The call is debounced - refreshing many times in quick succession only hits the network once every 5 minutes, and only when the cached lease is within 24 h of expiry or the last successful refresh is older than 6 h.

Every time the manager enters .licensed, it schedules an internal Task that wakes up 1 hour before the cached lease’s expiresAt and forces a refresh. No consumer code required - this runs for as long as your app keeps the manager alive.

Transient network failures during refresh are silently ignored, so a flaky connection never boots a paying user. An explicit invalid reply from Keylight does flip state to .invalid - the server is authoritative.

KeylightConfiguration.maxOfflineDays (default 15) is a hard backstop on top of the 7-day lease TTL. The SDK writes a lastValidatedOnline timestamp to the Keychain after every successful activate or validate; if that timestamp is older than maxOfflineDays, getCachedLease() rejects the cached lease and forces a network check on next launch. Set it lower (e.g. 7) for stricter enforcement, or higher for apps that legitimately spend long stretches offline. See Offline leases for the full picture.

KeylightProvider logs to the unified logging system under the dev.keylight subsystem. Every HTTP request is tagged with an 8-character request ID, sent to Keylight via the X-Keylight-Request-Id header and echoed back on the response. If you need Keylight support to correlate a specific call, share that request ID.

  • In-IDE. Xcode’s console shows providerLog lines during a debug session. Filter by subsystem:dev.keylight to isolate them.
  • Post-hoc on the device. Run:
    Terminal window
    log stream --predicate 'subsystem == "dev.keylight"' --level debug
    on macOS, or use Console.app with the same filter.
  • Requesting support. Every Keylight log line carries a [<requestId>] prefix. When filing an issue, include the request ID so we can look up the server-side view of that exact call.