mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import AtpAgent from '@atproto/api'
2import RNFS from 'react-native-fs'
3
4const TIMEOUT = 10e3 // 10s
5
6export function doPolyfill() {
7 AtpAgent.configure({fetch: fetchHandler})
8}
9
10interface FetchHandlerResponse {
11 status: number
12 headers: Record<string, string>
13 body: ArrayBuffer | undefined
14}
15
16async function fetchHandler(
17 reqUri: string,
18 reqMethod: string,
19 reqHeaders: Record<string, string>,
20 reqBody: any,
21): Promise<FetchHandlerResponse> {
22 const reqMimeType = reqHeaders['Content-Type'] || reqHeaders['content-type']
23 if (reqMimeType && reqMimeType.startsWith('application/json')) {
24 reqBody = JSON.stringify(reqBody)
25 } else if (
26 typeof reqBody === 'string' &&
27 (reqBody.startsWith('/') || reqBody.startsWith('file:'))
28 ) {
29 if (reqBody.endsWith('.jpeg') || reqBody.endsWith('.jpg')) {
30 // HACK
31 // React native has a bug that inflates the size of jpegs on upload
32 // we get around that by renaming the file ext to .bin
33 // see https://github.com/facebook/react-native/issues/27099
34 // -prf
35 const newPath = reqBody.replace(/\.jpe?g$/, '.bin')
36 await RNFS.moveFile(reqBody, newPath)
37 reqBody = newPath
38 }
39 // NOTE
40 // React native treats bodies with {uri: string} as file uploads to pull from cache
41 // -prf
42 reqBody = {uri: reqBody}
43 }
44
45 const controller = new AbortController()
46 const to = setTimeout(() => controller.abort(), TIMEOUT)
47
48 const res = await fetch(reqUri, {
49 method: reqMethod,
50 headers: reqHeaders,
51 body: reqBody,
52 signal: controller.signal,
53 })
54
55 const resStatus = res.status
56 const resHeaders: Record<string, string> = {}
57 res.headers.forEach((value: string, key: string) => {
58 resHeaders[key] = value
59 })
60 const resMimeType = resHeaders['Content-Type'] || resHeaders['content-type']
61 let resBody
62 if (resMimeType) {
63 if (resMimeType.startsWith('application/json')) {
64 resBody = await res.json()
65 } else if (resMimeType.startsWith('text/')) {
66 resBody = await res.text()
67 } else {
68 throw new Error('TODO: non-textual response body')
69 }
70 }
71
72 clearTimeout(to)
73
74 return {
75 status: resStatus,
76 headers: resHeaders,
77 body: resBody,
78 }
79}