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