* origin/main: (43 commits)
Release Prep 1.126.0 (#11015)
Fix chat input positioning on mobile android (#11013)
Disable selectable profile description on Android (#11002)
Fix CI - grant workflows permission for internal sync push (#11010)
Set apple team id via environment variable (#11008)
Fix 149/150 user limit for starter packs (#11001)
Nightly source-language update
Fix GrowthBook exposure did mis-attribution across account switches (#11000)
Add advanced search UI (#10992)
Fail video duration check before compression (#10999)
Add app language: Czech (`cs`) (#10994)
Clean up type/lint errors in `modules` (#10996)
Bump actions/download-artifact from 7.0.0 to 8.0.1 (#10971)
Nightly source-language update
Change dialog label and header from 'Invite Friends' to 'Share Profile' (#10987)
Add placeholder, empty-value, and onConfirm support to DateField (#10993)
Add video upload telemetry events (#10991)
Hide autocomplete suggestions when input loses focus (#10989)
Increase unread cap to 99+ (#10985)
Add icon to AppLanguageDropdown (#10977)
...
0.20.23 ships `additionalVerificationMethods` on the generated
ConfigRegion type, so the client-side AgeAssuranceConfigRegion
intersection and AgeAssuranceVerificationMethod alias are no longer
needed. Read the field directly off the generated type and type the
debug config as AppBskyAgeassuranceDefs.Config.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Model only the methods permitted *in addition to* the always-supported
KWS flow, rather than a full method list. This prevents a region from
being configured as device-only, which would lock out web and any
platform without the native age API.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
* persist startup queries
* Use IDB for query storage (#9687)
* Add storage abstraction for persisted query data
Introduce a platform-specific storage abstraction layer for react-query
persistence:
- Native: Uses MMKV for high-performance synchronous storage
- Web: Uses IndexedDB via the `idb` library for efficient async storage
This replaces the previous AsyncStorage implementation with more performant
platform-native solutions. The abstraction maintains API compatibility with
@tanstack/query-async-storage-persister.
* Refactor storage abstraction to use factory pattern
Change createPersistedQueryStorage to a factory function that accepts a
storage ID, allowing multiple isolated storage instances:
- Native: Each instance gets its own MMKV store
- Web: Each instance gets its own IndexedDB database
Adopt the factory pattern in:
- react-query.tsx: Uses 'persisted_queries' storage
- ageAssurance/data.tsx: Uses 'age_assurance' storage
This provides better separation between different query client caches
and allows each to be managed independently.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Refactor to use archival storage
(cherry picked from commit a773b40e41c96f821cd32260919ce1437c0fc3ab)
* Improve archive db types
(cherry picked from commit 80e4959ba2aa00c984c26aed2f7dfae1095720b0)
* rm idb
* clear on logout, bust on app version
* create abstraction for persisting queries, make gcTime infinite
* Rm abstraction
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Eric Bailey <git@esb.lol>
* WIP
* Clean up growthbook code, integrate into init and sessions
* Move everything out of React
* Add metrics client
* Move to separate file
* Shared metadata cache
* Ensure we update metadata when session ID changes
* Ensure userMetadata is cleared when logging out
* WIP revamp
* Integrate feature gates into analytics context
* Clean up old code
* Fix useMeta util
* Some comments and cleanup
* Add logger to base analytics context
* Refactor current route handling
* Rip out LogEvent from navigation
* Update tracking endpoint
* Migrate toClout
* Clear out statsig client
* Add todo, reset logger readme
* Ope fix statsig noop
* Refactor logging in feed-feedback, add debug logging to metrics client
* Remove LogEvents alias for Metrics
* Prefer root package export
* Remove Metrics alias from logger
* [APP-1782] Migrate to new analytics APIs (#9735)
* Migrate logEvent to useAnalytics
* Migrate logger.metric to useAnalytics
* Migrate tricky spot, fix types
* Migrate remaining tricky spot
* Missed one
* Remove metric() from logger
* Migrate useGate to useAnalytics
* Remove all other StatSig mentions
* Update event payload
* Update logger tests
* Mock expo method
* Fix session ID bug
* Add session ID test
* Add test for metrics client
* Clarify intent
* Clean up core analytics file
* Clean up the call once utils
* Fix TODO
* Fix TODO
* Fix TODO
* Fix TODO
* Fix TODO
* Remove debug code
* Fix navigation context
* OK nav context is not working, todo
* Checkpoint: works but feels hacky
* Fix navigation context issue
* Improve feature API
* Improve metric logging
* Update logger tests