tangled
alpha
login
or
join now
jeanmachine.dev
/
witchsky.app
forked from
jollywhoppers.com/witchsky.app
0
fork
atom
Bluesky app fork with some witchin' additions 💫
0
fork
atom
overview
issues
pulls
pipelines
fix age assurance and geolocation breaking things
xan.lol
1 month ago
62334b9f
70b84206
verified
This commit was signed with the committer's
known signature
.
xan.lol
SSH Key Fingerprint:
SHA256:7Zs+dcly5YqxBg7v8XsE1uPMYCobHKBw7CDiNxpmSrY=
+33
-85
4 changed files
expand all
collapse all
unified
split
src
ageAssurance
data.tsx
env
common.ts
geolocation
const.ts
service.ts
+17
-28
src/ageAssurance/data.tsx
···
3
3
type AppBskyAgeassuranceDefs,
4
4
type AppBskyAgeassuranceGetConfig,
5
5
type AppBskyAgeassuranceGetState,
6
6
-
AtpAgent,
6
6
+
type AtpAgent,
7
7
getAgeAssuranceRegionConfig,
8
8
} from '@atproto/api'
9
9
import AsyncStorage from '@react-native-async-storage/async-storage'
···
13
13
import debounce from 'lodash.debounce'
14
14
15
15
import {networkRetry} from '#/lib/async/retry'
16
16
-
import {PUBLIC_BSKY_SERVICE} from '#/lib/constants'
17
16
import {getAge} from '#/lib/strings/time'
18
17
import {
19
18
hasSnoozedBirthdateUpdateForDid,
···
91
90
export const configQueryKey = ['config']
92
91
export async function getConfig() {
93
92
if (debug.enabled) return debug.resolve(debug.config)
94
94
-
const agent = new AtpAgent({
95
95
-
service: PUBLIC_BSKY_SERVICE,
96
96
-
})
97
97
-
const res = await agent.app.bsky.ageassurance.getConfig()
98
98
-
return res.data
93
93
+
return {
94
94
+
regions: [],
95
95
+
}
99
96
}
100
97
export function getConfigFromCache():
101
98
| AppBskyAgeassuranceGetConfig.OutputSchema
···
179
176
export function createServerStateQueryKey({did}: {did: string}) {
180
177
return ['serverState', did]
181
178
}
182
182
-
export async function getServerState({agent}: {agent: AtpAgent}) {
179
179
+
export async function getServerState() {
183
180
if (debug.enabled && debug.serverState)
184
181
return debug.resolve(debug.serverState)
185
185
-
const geolocation = device.get(['mergedGeolocation'])
186
186
-
if (!geolocation || !geolocation.countryCode) {
187
187
-
logger.error(`getServerState: missing geolocation countryCode`)
188
188
-
return
182
182
+
return {
183
183
+
state: {
184
184
+
lastInitiatedAt: '2025-07-14T14:22:43.912Z',
185
185
+
status: 'assured' as const,
186
186
+
access: 'full' as const,
187
187
+
},
188
188
+
metadata: {
189
189
+
accountCreatedAt: '2022-11-17T00:35:16.391Z',
190
190
+
},
189
191
}
190
190
-
const {data} = await agent.app.bsky.ageassurance.getState({
191
191
-
countryCode: geolocation.countryCode,
192
192
-
regionCode: geolocation.regionCode,
193
193
-
})
194
194
-
const did = getDidFromAgentSession(agent)
195
195
-
if (data && did && createdAtCache.has(did)) {
196
196
-
/*
197
197
-
* If account was just created, just use the local cache if available. On
198
198
-
* subsequent reloads, the server should have the correct value.
199
199
-
*/
200
200
-
data.metadata.accountCreatedAt = createdAtCache.get(did)
201
201
-
}
202
202
-
return data ?? null
203
192
}
204
193
export function getServerStateFromCache({
205
194
did,
···
226
215
227
216
try {
228
217
logger.debug(`prefetchServerState: resolving...`)
229
229
-
const res = await networkRetry(3, () => getServerState({agent}))
218
218
+
const res = await networkRetry(3, () => getServerState())
230
219
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(qk, res)
231
220
} catch (e: any) {
232
221
logger.warn(`prefetchServerState: failed`, {
···
238
227
const did = getDidFromAgentSession(agent)
239
228
if (!did) return
240
229
logger.debug(`refetchServerState: fetching...`)
241
241
-
const res = await networkRetry(3, () => getServerState({agent}))
230
230
+
const res = await networkRetry(3, () => getServerState())
242
231
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
243
232
createServerStateQueryKey({did}),
244
233
res,
···
277
266
},
278
267
queryKey: createServerStateQueryKey({did: did!}),
279
268
async queryFn() {
280
280
-
return getServerState({agent})
269
269
+
return getServerState()
281
270
},
282
271
},
283
272
qc,
+5
-10
src/env/common.ts
···
123
123
: Number(process.env.EXPO_PUBLIC_GCP_PROJECT_ID)
124
124
125
125
/**
126
126
-
* URLs for the app config web worker. Can be a
127
127
-
* locally running server, see `env.example` for more.
128
128
-
*/
129
129
-
export const GEOLOCATION_DEV_URL = process.env.GEOLOCATION_DEV_URL
130
130
-
export const GEOLOCATION_PROD_URL = `https://ip.bsky.app`
131
131
-
export const GEOLOCATION_URL = IS_DEV
132
132
-
? (GEOLOCATION_DEV_URL ?? GEOLOCATION_PROD_URL)
133
133
-
: GEOLOCATION_PROD_URL
134
134
-
135
135
-
/**
136
126
* URLs for the live-event config web worker. Can be a
137
127
* locally running server, see `env.example` for more.
138
128
*/
129
129
+
export const LIVE_EVENTS_DEV_URL = process.env.LIVE_EVENTS_DEV_URL
130
130
+
export const LIVE_EVENTS_PROD_URL = `https://live-events.workers.bsky.app`
131
131
+
export const LIVE_EVENTS_URL = IS_DEV
132
132
+
? (LIVE_EVENTS_DEV_URL ?? LIVE_EVENTS_PROD_URL)
133
133
+
: LIVE_EVENTS_PROD_URL
+1
-2
src/geolocation/const.ts
···
1
1
-
import {GEOLOCATION_URL} from '#/env'
2
1
import {type Geolocation} from '#/geolocation/types'
3
2
4
4
-
export const GEOLOCATION_SERVICE_URL = `${GEOLOCATION_URL}/geolocation`
3
3
+
export const GEOLOCATION_SERVICE_URL = '' // No longer needed
5
4
6
5
/**
7
6
* Default geolocation config.
+10
-45
src/geolocation/service.ts
···
1
1
import {useEffect, useState} from 'react'
2
2
import EventEmitter from 'eventemitter3'
3
3
4
4
-
import {networkRetry} from '#/lib/async/retry'
5
5
-
import {
6
6
-
FALLBACK_GEOLOCATION_SERVICE_RESPONSE,
7
7
-
GEOLOCATION_SERVICE_URL,
8
8
-
} from '#/geolocation/const'
4
4
+
import {FALLBACK_GEOLOCATION_SERVICE_RESPONSE} from '#/geolocation/const'
9
5
import * as debug from '#/geolocation/debug'
10
6
import {logger} from '#/geolocation/logger'
11
7
import {type Geolocation} from '#/geolocation/types'
12
8
import {device} from '#/storage'
13
9
10
10
+
const geolocationData = FALLBACK_GEOLOCATION_SERVICE_RESPONSE
14
11
const events = new EventEmitter()
15
12
const EVENT = 'geolocation-service-response-updated'
16
13
const emitGeolocationServiceResponseUpdate = (data: Geolocation) => {
···
25
22
}
26
23
}
27
24
28
28
-
async function fetchGeolocationServiceData(
29
29
-
url: string,
30
30
-
): Promise<Geolocation | undefined> {
25
25
+
async function fetchGeolocationServiceData(): Promise<Geolocation | undefined> {
31
26
if (debug.enabled) return debug.resolve(debug.geolocation)
32
32
-
const res = await fetch(url)
33
33
-
if (!res.ok) {
34
34
-
throw new Error(`fetchGeolocationServiceData failed ${res.status}`)
35
35
-
}
36
36
-
return res.json() as Promise<Geolocation>
27
27
+
// Return local geolocation data instead of making HTTP request
28
28
+
return geolocationData as Geolocation
37
29
}
38
30
39
31
/**
···
63
55
} else {
64
56
logger.debug(`resolve(): initiating`)
65
57
66
66
-
/**
67
67
-
* THIS PROMISE SHOULD NEVER `reject()`! We want the app to proceed with
68
68
-
* startup, even if geolocation resolution fails.
69
69
-
*/
70
58
geolocationServicePromise = new Promise(async resolvePromise => {
71
59
let success = false
72
60
···
75
63
device.set(['geolocationServiceResponse'], response)
76
64
emitGeolocationServiceResponseUpdate(response)
77
65
} else {
78
78
-
// endpoint should throw on all failures, this is insurance
79
66
throw new Error(`fetchGeolocationServiceData returned no data`)
80
67
}
81
68
}
82
69
83
70
try {
84
84
-
// Try once, fail fast
85
85
-
const config = await fetchGeolocationServiceData(
86
86
-
GEOLOCATION_SERVICE_URL,
87
87
-
)
71
71
+
// Use local data - no need to retry or handle network errors
72
72
+
const config = await fetchGeolocationServiceData()
88
73
cacheResponseOrThrow(config)
89
74
success = true
90
75
} catch (e: any) {
91
91
-
logger.debug(
92
92
-
`resolve(): fetchGeolocationServiceData failed initial request`,
93
93
-
{
94
94
-
safeMessage: e.message,
95
95
-
},
96
96
-
)
97
97
-
98
98
-
// retry 3 times, but don't await, proceed with default
99
99
-
networkRetry(3, () =>
100
100
-
fetchGeolocationServiceData(GEOLOCATION_SERVICE_URL),
101
101
-
)
102
102
-
.then(config => {
103
103
-
cacheResponseOrThrow(config)
104
104
-
})
105
105
-
.catch((err: any) => {
106
106
-
// complete fail closed
107
107
-
logger.debug(
108
108
-
`resolve(): fetchGeolocationServiceData failed retries`,
109
109
-
{
110
110
-
safeMessage: err.message,
111
111
-
},
112
112
-
)
113
113
-
})
76
76
+
logger.debug(`resolve(): fetchGeolocationServiceData failed`, {
77
77
+
safeMessage: e.message,
78
78
+
})
114
79
} finally {
115
80
resolvePromise({success})
116
81
}