[sub-spm-optional-products] Add LCECryptoKit and LCFeatureControl as optional sub-SPM products
LCEssentials installs standalone; each sub target-depends on it so linking a sub's product always pulls LCEssentials in too, without the consumer having to declare it separately. - LCECryptoKit: internalized from the remote LCECryptoKitBinary git dependency (embedded token URL removed) into a local binaryTarget vendoring Frameworks/LCECryptoKit.xcframework. LCECryptoKitManager moved out of LCEssentials core into its own LCECryptoKitManager target/product; the no-op fallback for when the binary wasn't linked is gone (breaking change for existing consumers, see decisions/2026-09-15-sub-spm-optional-products.md). - LCFeatureControl: new product wrapping Atomenta's Feature Control API (flag evaluation with TTL cache + safe-degrade fallback to defaults, notifications inbox, batched exposure telemetry). 45 new tests.
This commit is contained in:
18
Sources/LCFeatureControl/FeatureControlDateParsing.swift
Normal file
18
Sources/LCFeatureControl/FeatureControlDateParsing.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
import Foundation
|
||||
|
||||
/// Parses the ISO-8601 timestamps Atomenta sends (`2026-04-16T12:00:00.000Z`, with
|
||||
/// milliseconds). `LCEssentials.API`'s internal `JSONDecoder` uses the default
|
||||
/// (`.deferredToDate`, numeric epoch) strategy, so `Date` fields on wire models
|
||||
/// decode the raw string manually instead of relying on `Decodable`'s default
|
||||
/// date handling.
|
||||
enum FeatureControlDateParsing {
|
||||
static func parse(_ string: String) -> Date? {
|
||||
let withFractional = ISO8601DateFormatter()
|
||||
withFractional.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
if let date = withFractional.date(from: string) { return date }
|
||||
|
||||
let plain = ISO8601DateFormatter()
|
||||
plain.formatOptions = [.withInternetDateTime]
|
||||
return plain.date(from: string)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user