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