Invert the flag's polarity and name so it reads like the other "enable"
booleans in the debug module: useMockDeviceSignalsAPIResponse defaults to
true (mock the native response), set false to hit the real API.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a US-TX region to the debug config with verificationMethods
['device', 'kws'], plus a useRealDeviceSignalsAPI escape hatch (default
off) so the real native age API can be exercised in debug mode instead of
the faked deviceSignals.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename getAssuredAgeFromDeviceSignals to getAgeAssuranceDataFromDeviceSignals
and return an object instead of a bare number, leaving room to derive more
rule-engine inputs from the native response (declared vs. guardian-declared,
parental controls, platform verification status) as the rules grow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
While the native OS age prompt is up, swap the Verify button icon for a
Loader and disable it to prevent double-taps. Scoped to the device path;
the KWS fallback opens a dialog synchronously.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Persist on-device age signals client-side as a map keyed by
country[-region] string, so multiple regions can each retain their own
grant. Reads resolve to the user's current region via mergedGeolocation
(react-query `select` for the hook, a shared helper for the out-of-band
path), so a grant captured in one region never unlocks another.
- AgeAssuranceDeviceSignals is now a region-keyed map
- setDeviceSignalsForRegion merges a region's signals into the map
- useDeviceSignalsQuery select-resolves to the current region; cache
keeps the full map for the writer + persistence
- getAssuredAgeFromDeviceSignals takes the already-resolved signals
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
expo-age-range uses SDK-aligned versioning; 56.x targets Expo SDK 56,
but we're on SDK 54. Pin to the 0.2.x line (0.2.17) instead.
Restore the iOS patch (in pnpm format): the 0.2.x Swift captures a
non-Sendable appContext into a MainActor.run closure, which fails to
compile on our toolchain with "task or actor-isolated value cannot be
sent". Capturing utilities into a local nonisolated(unsafe) var before
the closure resolves it. Verified: build fails without the patch, passes
with it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Device assurance can't be verified server-side (the OS gives only age
bounds, no signed attestation), so it's persisted client-side only. Bind
each cached grant to the region it was captured in so a TX grant can't
unlock another region.
- Add AgeAssuranceDeviceSignals (signals + originRegion); store the
region-tagged record in the persisted cache instead of the raw response
- getAssuredAgeFromDeviceSignals now requires the current region to match
the capture region
- Gate the native age request to native platforms (web returns a
misleading default); web/new-device/declined falls back to KWS
- TX allows ['device', 'kws'] so the fallback path is real
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wire the expo-age-range device signals (already plumbed) into the age
assurance access decision, gated per-region.
- Model verificationMethods on region config (AgeAssuranceConfigRegion)
and add a debug US/TX region permitting the 'device' method
- Add region accessors + getAssuredAgeFromDeviceSignals in util
- Surface deviceSignals through the AA context and feed lowerBound in as
assuredAge, matching the existing IfAssuredOverAge rules
- NoAccessScreen "Verify now" now prompts the OS in device regions and
falls back to the KWS dialog when unavailable/insufficient
- Keep useDeviceSignalsQuery disabled so we never prompt on load; restore
from the persisted cache only
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>