Harden App Store build for review
This commit is contained in:
@@ -82,8 +82,8 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
|
||||
/// Diagnostics beacon tag: empty → derive from the intent type name. A
|
||||
/// widget kind that shares an intent (the A/B test small widget reuses the
|
||||
/// medium intent) passes an explicit tag so its beacons stay
|
||||
/// distinguishable in the relay log and keychain slots.
|
||||
/// medium intent) passes an explicit tag so its keychain diagnostic slots
|
||||
/// stay distinguishable.
|
||||
var beaconTag: String = ""
|
||||
|
||||
func placeholder(in context: Context) -> FuelPriceEntry {
|
||||
@@ -122,10 +122,9 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
}
|
||||
|
||||
/// Fire-and-forget diagnostics beacon: writes the entry state to keychain
|
||||
/// (app-readable, one slot per intent type) and GETs the relay so its
|
||||
/// access log records that a widget timeline actually ran in the
|
||||
/// extension and what it produced. Deliberately outside the timeline
|
||||
/// result — can never affect rendering.
|
||||
/// (app-readable, one slot per intent type) and records what a widget
|
||||
/// timeline produced for Settings → Widget Diagnostics. Deliberately
|
||||
/// outside the timeline result — can never affect rendering.
|
||||
private func writeDiagBeacon(entry: FuelPriceEntry) {
|
||||
let d = entry.data
|
||||
let intentType = beaconTag.isEmpty ? String(describing: Configuration.self) : beaconTag
|
||||
@@ -137,29 +136,8 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
"station":"\(first?.name ?? "")","price":\(first?.prices[d.fuel] ?? -1)}
|
||||
"""
|
||||
FuelStore.saveWidgetDiag(json, intentType: intentType)
|
||||
// The relay GET is dev-only (same flag as the app beacon): consumers
|
||||
// must never make a local-network attempt. The local app-group diag
|
||||
// write above stays — Settings → Widget Diagnostics reads that.
|
||||
guard FuelStore.loadRelayFallbackEnabled() else { return }
|
||||
guard var components = URLComponents(
|
||||
url: RelayFuelProvider().baseURL.appendingPathComponent("api/v1/widget-diag"),
|
||||
resolvingAgainstBaseURL: false
|
||||
) else { return }
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "intent", value: intentType),
|
||||
URLQueryItem(name: "source", value: d.locationSource),
|
||||
URLQueryItem(name: "n", value: String(d.stations.count)),
|
||||
URLQueryItem(name: "fuel", value: d.fuel.rawValue),
|
||||
URLQueryItem(name: "sort", value: d.sort.rawValue),
|
||||
URLQueryItem(name: "fav", value: d.isFavourites ? "1" : "0"),
|
||||
URLQueryItem(name: "station", value: first?.name ?? ""),
|
||||
URLQueryItem(name: "price", value: String(first?.prices[d.fuel] ?? -1)),
|
||||
]
|
||||
guard let url = components.url else { return }
|
||||
let request = RelayFuelProvider.relayRequest(url, client: "widget", timeout: 2)
|
||||
Task {
|
||||
_ = try? await URLSession.shared.data(for: request)
|
||||
}
|
||||
// Local app-group diagnostics only. No network beacon is sent: the
|
||||
// App Store build must not contain a private LAN relay fallback.
|
||||
}
|
||||
|
||||
private func makeEntryCore(configuration: Configuration) async -> FuelPriceEntry {
|
||||
@@ -201,7 +179,7 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
// Favourites tab drag-to-reorder). Not radius-bound — a favourite
|
||||
// in Edinburgh shows on a widget in London. Prices come from the
|
||||
// keychain snapshot (the app refreshes favourite prices into
|
||||
// keychain after every fetch), or fresher from a focused relay
|
||||
// keychain after every fetch), or fresher from a focused mirror
|
||||
// fetch when a favourite happens to be in range. The small face
|
||||
// renders the FIRST of this list — the user's top favourite for
|
||||
// the chosen fuel. (The old per-widget pinned-favourite picker
|
||||
@@ -223,7 +201,7 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
ordered = refreshed
|
||||
} else {
|
||||
// 3a) Load stations. The widget prefers its OWN focused fetch from the
|
||||
// relay so it shows real prices even when the app-group cache isn't
|
||||
// public mirror so it shows real prices even when the app-group cache isn't
|
||||
// shared (SideStore free accounts don't provision the group, which
|
||||
// previously left the widget stuck on sample data). Falls back to the
|
||||
// shared cache, then to samples.
|
||||
@@ -289,65 +267,21 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
)
|
||||
}
|
||||
|
||||
/// One focused fetch around the widget's location. GitHub mirror FIRST —
|
||||
/// HTTPS, works anywhere, and the app-group day-cache usually makes it a
|
||||
/// local decode rather than a 2.8 MB download. The LAN relay only joins
|
||||
/// behind the dev flag (fuelboard.relayFallback); consumers must never
|
||||
/// attempt local-network access. Returns nil on any failure so callers
|
||||
/// fall back to cache/placeholder.
|
||||
/// One focused fetch around the widget's location. Public HTTPS mirror only;
|
||||
/// no private LAN fallback is attempted. Returns nil on any failure so
|
||||
/// callers fall back to cache/placeholder.
|
||||
private static func fetchFocused(near location: Coordinate, fuel: FuelType, radiusKM: Double) async -> [FuelStation]? {
|
||||
if let stations = try? await MirrorFuelProvider().fetchStations(
|
||||
near: location.lat, lng: location.lng, fuel: fuel, radiusKM: radiusKM) {
|
||||
return stations
|
||||
}
|
||||
guard FuelStore.loadRelayFallbackEnabled() else { return nil }
|
||||
var components = URLComponents(
|
||||
url: RelayFuelProvider().baseURL.appendingPathComponent("api/v1/stations"),
|
||||
resolvingAgainstBaseURL: false
|
||||
)!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "fuel", value: fuel.rawValue),
|
||||
URLQueryItem(name: "lat", value: String(location.lat)),
|
||||
URLQueryItem(name: "lng", value: String(location.lng)),
|
||||
URLQueryItem(name: "radius", value: String(radiusKM)),
|
||||
URLQueryItem(name: "limit", value: "500"),
|
||||
]
|
||||
let request = RelayFuelProvider.relayRequest(components.url!, client: "widget", timeout: 5)
|
||||
do {
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else { return nil }
|
||||
return try? FuelPriceProvider.decodeStations(from: data)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
try? await MirrorFuelProvider().fetchStations(
|
||||
near: location.lat, lng: location.lng, fuel: fuel, radiusKM: radiusKM)
|
||||
}
|
||||
|
||||
/// Fuel-only UK-wide fetch (no lat/lng/radius) — used when the widget has
|
||||
/// no location fix so the face shows real stations instead of sample
|
||||
/// data. GitHub mirror first (full dump + local fuel filter), relay only
|
||||
/// behind the dev flag. Same nil-on-failure semantics as fetchFocused.
|
||||
/// no location fix so the face shows real stations instead of sample data.
|
||||
/// Public HTTPS mirror only; same nil-on-failure semantics as fetchFocused.
|
||||
private static func fetchFuelOnly(fuel: FuelType, limit: Int) async -> [FuelStation]? {
|
||||
if let stations = try? await MirrorFuelProvider().fetchStations(
|
||||
near: nil, lng: nil, fuel: fuel, radiusKM: nil) {
|
||||
return Array(stations.filter { $0.prices[fuel] != nil }.prefix(limit))
|
||||
}
|
||||
guard FuelStore.loadRelayFallbackEnabled() else { return nil }
|
||||
var components = URLComponents(
|
||||
url: RelayFuelProvider().baseURL.appendingPathComponent("api/v1/stations"),
|
||||
resolvingAgainstBaseURL: false
|
||||
)!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "fuel", value: fuel.rawValue),
|
||||
URLQueryItem(name: "limit", value: String(limit)),
|
||||
]
|
||||
let request = RelayFuelProvider.relayRequest(components.url!, client: "widget", timeout: 5)
|
||||
do {
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else { return nil }
|
||||
return try? FuelPriceProvider.decodeStations(from: data)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
guard let stations = try? await MirrorFuelProvider().fetchStations(
|
||||
near: nil, lng: nil, fuel: fuel, radiusKM: nil) else { return nil }
|
||||
return Array(stations.filter { $0.prices[fuel] != nil }.prefix(limit))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user