[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:
33
Sources/LCFeatureControl/FeatureControlJSON.swift
Normal file
33
Sources/LCFeatureControl/FeatureControlJSON.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
import Foundation
|
||||
|
||||
/// Minimal "any JSON" box for a flag's `payload`, which the backend declares as
|
||||
/// `additionalProperties: true` (arbitrary shape). No force operations — an
|
||||
/// unrecognized shape throws a `DecodingError`, it never crashes.
|
||||
public indirect enum FeatureControlJSON: Decodable, Sendable, Equatable {
|
||||
case null
|
||||
case bool(Bool)
|
||||
case number(Double)
|
||||
case string(String)
|
||||
case array([FeatureControlJSON])
|
||||
case object([String: FeatureControlJSON])
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
if container.decodeNil() {
|
||||
self = .null
|
||||
} else if let value = try? container.decode(Bool.self) {
|
||||
self = .bool(value)
|
||||
} else if let value = try? container.decode(Double.self) {
|
||||
self = .number(value)
|
||||
} else if let value = try? container.decode(String.self) {
|
||||
self = .string(value)
|
||||
} else if let value = try? container.decode([FeatureControlJSON].self) {
|
||||
self = .array(value)
|
||||
} else if let value = try? container.decode([String: FeatureControlJSON].self) {
|
||||
self = .object(value)
|
||||
} else {
|
||||
throw DecodingError.dataCorruptedError(in: container,
|
||||
debugDescription: "Unsupported JSON value for FeatureControlJSON")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user