import {useCallback, useState} from 'react' import {View} from 'react-native' import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react' import {Trans} from '@lingui/react/macro' import {DM_SERVICE_HEADERS} from '#/lib/constants' import {saveBytesToDisk} from '#/lib/media/manip' import {logger} from '#/logger' import {useAgent} from '#/state/session' import {atoms as a, useTheme, web} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {Download_Stroke2_Corner0_Rounded as DownloadIcon} from '#/components/icons/Download' import {InlineLinkText} from '#/components/Link' import {Loader} from '#/components/Loader' import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' export function ExportCarDialog({ control, }: { control: Dialog.DialogControlProps }) { const {_} = useLingui() const t = useTheme() const agent = useAgent() const [loading, setLoading] = useState<'repo' | 'chat' | false>(false) const download = useCallback(async () => { if (!agent.session) { return // shouldnt ever happen } try { setLoading('repo') const did = agent.session.did const downloadRes = await agent.com.atproto.sync.getRepo({did}) const saveRes = await saveBytesToDisk( 'repo.car', downloadRes.data, downloadRes.headers['content-type'] || 'application/vnd.ipld.car', ) if (saveRes) { Toast.show(_(msg`File saved successfully!`)) } } catch (e) { logger.error('Error occurred while downloading CAR file', {message: e}) Toast.show(_(msg`Error occurred while saving file`), {type: 'error'}) } finally { setLoading(false) control.close() } }, [_, control, agent]) const downloadChatData = useCallback(async () => { if (!agent.session) { return } try { setLoading('chat') // Using raw fetch because the XRPC client incorrectly tries to JSON-parse // application/jsonl responses (substring match on application/json). const res = await agent.sessionManager.fetchHandler( '/xrpc/chat.bsky.actor.exportAccountData', {headers: DM_SERVICE_HEADERS}, ) if (!res.ok) { throw new Error(`HTTP ${res.status}`) } const data = new Uint8Array(await res.arrayBuffer()) const saveRes = await saveBytesToDisk( 'chat.jsonl', data, res.headers.get('content-type') || 'application/jsonl', ) if (saveRes) { Toast.show(_(msg`File saved successfully!`)) } } catch (e) { logger.error('Error occurred while downloading chat data', {message: e}) Toast.show(_(msg`Error occurred while saving file`), {type: 'error'}) } finally { setLoading(false) control.close() } }, [_, control, agent]) return ( Export My Data Your account repository, containing all public data records, can be downloaded as a "CAR" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately. You can also download your chat data as a "JSONL" file. This file only includes chat messages that you have sent and does not include chat messages that you have received. This feature is in beta. You can read more about repository exports in{' '} this blogpost . ) }