diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-01-26 12:36:27 -0600 |
---|---|---|
committer | Paul Frazee <pfrazee@gmail.com> | 2023-01-26 12:36:27 -0600 |
commit | 751dfb20fd0d316da396e3c4fc53aaaaa8041dd1 (patch) | |
tree | 55c23e901903cfa19b6b9acc264df0d0637d66f0 /src/state/lib/api-polyfill.ts | |
parent | d6ec627c8cd32836e5ed494606318959ca17fca1 (diff) | |
download | voidsky-751dfb20fd0d316da396e3c4fc53aaaaa8041dd1.tar.zst |
Add web polyfills
Diffstat (limited to 'src/state/lib/api-polyfill.ts')
-rw-r--r-- | src/state/lib/api-polyfill.ts | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/state/lib/api-polyfill.ts b/src/state/lib/api-polyfill.ts new file mode 100644 index 000000000..be6f90f7a --- /dev/null +++ b/src/state/lib/api-polyfill.ts @@ -0,0 +1,76 @@ +import {sessionClient as AtpApi} from '@atproto/api' + +export function doPolyfill() { + AtpApi.xrpc.fetch = fetchHandler +} + +interface FetchHandlerResponse { + status: number + headers: Record<string, string> + body: ArrayBuffer | undefined +} + +async function fetchHandler( + reqUri: string, + reqMethod: string, + reqHeaders: Record<string, string>, + reqBody: any, +): Promise<FetchHandlerResponse> { + const reqMimeType = reqHeaders['Content-Type'] || reqHeaders['content-type'] + if (reqMimeType && reqMimeType.startsWith('application/json')) { + reqBody = JSON.stringify(reqBody) + } else if ( + typeof reqBody === 'string' && + (reqBody.startsWith('/') || reqBody.startsWith('file:')) + ) { + if (reqBody.endsWith('.jpeg') || reqBody.endsWith('.jpg')) { + // HACK + // React native has a bug that inflates the size of jpegs on upload + // we get around that by renaming the file ext to .bin + // see https://github.com/facebook/react-native/issues/27099 + // -prf + const newPath = reqBody.replace(/\.jpe?g$/, '.bin') + await RNFS.moveFile(reqBody, newPath) + reqBody = newPath + } + // NOTE + // React native treats bodies with {uri: string} as file uploads to pull from cache + // -prf + reqBody = {uri: reqBody} + } + + const controller = new AbortController() + const to = setTimeout(() => controller.abort(), TIMEOUT) + + const res = await fetch(reqUri, { + method: reqMethod, + headers: reqHeaders, + body: reqBody, + signal: controller.signal, + }) + + const resStatus = res.status + const resHeaders: Record<string, string> = {} + res.headers.forEach((value: string, key: string) => { + resHeaders[key] = value + }) + const resMimeType = resHeaders['Content-Type'] || resHeaders['content-type'] + let resBody + if (resMimeType) { + if (resMimeType.startsWith('application/json')) { + resBody = await res.json() + } else if (resMimeType.startsWith('text/')) { + resBody = await res.text() + } else { + throw new Error('TODO: non-textual response body') + } + } + + clearTimeout(to) + + return { + status: resStatus, + headers: resHeaders, + body: resBody, + } +} |