From a0881e4169ef3b3fb8c32da867ebeaa8d312f9a6 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 23 Jul 2026 14:15:09 -0500 Subject: [PATCH] Update API package and filter AA configs by platform (#11244) (cherry picked from commit a53df16e8261293808aff373f29f6e2cf54af878) --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- src/ageAssurance/const.ts | 19 ++++++++++++++++++- src/ageAssurance/debug.ts | 5 +++-- src/ageAssurance/util.test.ts | 31 +++++++++++++++++++++++++++++++ src/ageAssurance/util.ts | 6 ++++++ 6 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 src/ageAssurance/util.test.ts diff --git a/package.json b/package.json index 3800dca11f..426fe46374 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "prettier": "prettier --check ." }, "dependencies": { - "@atproto/api": "0.20.32", + "@atproto/api": "0.20.33", "@atproto/common-web": "0.5.6", "@atproto/syntax": "0.7.2", "@bitdrift/react-native": "^0.6.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fcabd373b6..c0d9ea6403 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -242,8 +242,8 @@ importers: .: dependencies: '@atproto/api': - specifier: 0.20.32 - version: 0.20.32 + specifier: 0.20.33 + version: 0.20.33 '@atproto/common-web': specifier: 0.5.6 version: 0.5.6 @@ -862,8 +862,8 @@ packages: graphql: optional: true - '@atproto/api@0.20.32': - resolution: {integrity: sha512-P6Lh6+PR+x0/HHdEbmwZ5e2uvrzViEeobHWHoEc7KTaKJ/bQQu39z2wfBrG4dOTEC/OcOhFYhAhepo0VGIOeAQ==} + '@atproto/api@0.20.33': + resolution: {integrity: sha512-3YpnBVMieQFWetLvqibn2yG6vhNZ7ozSi/EUujuGcvYXt9g/NrvmHufaUtrXCasp2mHDI7t7UG5sLEBg6YNEJw==} engines: {node: '>=22'} '@atproto/common-web@0.5.6': @@ -9123,7 +9123,7 @@ snapshots: '@0no-co/graphql.web@1.2.0': {} - '@atproto/api@0.20.32': + '@atproto/api@0.20.33': dependencies: '@atproto/common-web': 0.5.6 '@atproto/lexicon': 0.7.7 diff --git a/src/ageAssurance/const.ts b/src/ageAssurance/const.ts index f410d63489..326552681c 100644 --- a/src/ageAssurance/const.ts +++ b/src/ageAssurance/const.ts @@ -4,13 +4,30 @@ import { } from '@atproto/api' import {AgeAssuranceAccess} from '#/ageAssurance/types' -import {ANDROID_API_LEVEL, IOS_MAJOR_VERSION, IS_ANDROID, IS_IOS} from '#/env' +import { + ANDROID_API_LEVEL, + IOS_MAJOR_VERSION, + IS_ANDROID, + IS_IOS, + IS_WEB, +} from '#/env' /** * Minimum age required to access the app at all. */ export const MIN_ACCESS_AGE = 13 +/** + * The identifier for the current platform, matching the `knownValues` of the + * `platforms` property on `app.bsky.ageassurance.defs#configRegion`. Used to + * filter out region configs that don't apply to this platform. + */ +export const AGE_ASSURANCE_PLATFORM: 'web' | 'ios' | 'android' = IS_WEB + ? 'web' + : IS_IOS + ? 'ios' + : 'android' + /** * Whether the current device can provide the native on-device age signals we * use for age assurance (via `expo-age-range`). We gate on OS version because diff --git a/src/ageAssurance/debug.ts b/src/ageAssurance/debug.ts index 8a828a00e0..74121976ca 100644 --- a/src/ageAssurance/debug.ts +++ b/src/ageAssurance/debug.ts @@ -59,9 +59,10 @@ export const config: AppBskyAgeassuranceDefs.Config = { ], }, { - // On-device verification region. KWS is included as a fallback for - // platforms without the native age API (e.g. web) or when the device + // On-device verification region, native-only (web users in TX are not + // age assured). KWS is included as a fallback for when the device // result is insufficient. + platforms: ['ios', 'android'], countryCode: 'US', regionCode: 'TX', minAccessAge: 18, diff --git a/src/ageAssurance/util.test.ts b/src/ageAssurance/util.test.ts new file mode 100644 index 0000000000..1da131b920 --- /dev/null +++ b/src/ageAssurance/util.test.ts @@ -0,0 +1,31 @@ +import {getAgeAssuranceRegionConfig} from '@atproto/api' + +import {getAgeAssuranceRegionConfigForGeolocation} from '#/ageAssurance/util' + +jest.mock('#/ageAssurance/data') +jest.mock('@atproto/api', () => ({ + ...jest.requireActual('@atproto/api'), + getAgeAssuranceRegionConfig: jest.fn(), +})) + +/* + * Platform-based region filtering itself is implemented and tested in + * `@atproto/api` (see `getAgeAssuranceRegionConfig`). What we own - and test + * here - is that region resolution passes the current platform through. The + * jest preset is `jest-expo/ios`, so `AGE_ASSURANCE_PLATFORM` resolves to + * `ios` in these tests. + */ +describe('getAgeAssuranceRegionConfigForGeolocation', () => { + it('passes the current platform to the SDK region matcher', () => { + const config = {regions: []} + getAgeAssuranceRegionConfigForGeolocation(config, { + countryCode: 'US', + regionCode: 'TX', + }) + expect(getAgeAssuranceRegionConfig).toHaveBeenCalledWith(config, { + countryCode: 'US', + regionCode: 'TX', + platform: 'ios', + }) + }) +}) diff --git a/src/ageAssurance/util.ts b/src/ageAssurance/util.ts index ecd6468339..2bceab4d16 100644 --- a/src/ageAssurance/util.ts +++ b/src/ageAssurance/util.ts @@ -11,6 +11,7 @@ import {getAge} from '#/lib/strings/time' import {regionName} from '#/locale/helpers' import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/const' import { + AGE_ASSURANCE_PLATFORM, DEVICE_SIGNALS_SUPPORTED, FALLBACK_REGION_CONFIG, MIN_ACCESS_AGE, @@ -29,6 +30,10 @@ import {USRegionNameToRegionCode} from '#/geolocation/util' * Resolves a geolocation to its matched age assurance region config, or * undefined when the geolocation matches no AA region. * + * Regions scoped to other platforms via `platforms` are passed over entirely, + * as if they weren't in the config - a later region matching the same + * geolocation can still apply. + * * This is the single source of truth for geolocation -> region resolution. * Device signals are written and read back under a key derived from the * matched region (see `createRegionKey`), so every site that resolves a region @@ -42,6 +47,7 @@ export function getAgeAssuranceRegionConfigForGeolocation( return getAgeAssuranceRegionConfig(config, { countryCode: geolocation.countryCode ?? '', regionCode: geolocation.regionCode, + platform: AGE_ASSURANCE_PLATFORM, }) }