UNPKG

megalodon

Version:

Fediverse API client for node.js and browser

1,707 lines 58 kB
import { OAuth2Client } from '@badgateway/oauth2-client';
import FormData from 'form-data';
import { parseLinkHeader } from './parse_link_header.js';
import FriendicaAPI from './friendica/api_client.js';
import { NotImplementedError } from './megalodon.js';
import { NO_REDIRECT, DEFAULT_SCOPE, DEFAULT_UA } from './default.js';
import * as FriendicaOAuth from './friendica/oauth.js';
import { UnknownNotificationTypeError } from './notification.js';
export default class Friendica {
    client;
    baseUrl;
    constructor(baseUrl, accessToken = null, userAgent = DEFAULT_UA) {
        let token = '';
        if (accessToken) {
            token = accessToken;
        }
        let agent = DEFAULT_UA;
        if (userAgent) {
            agent = userAgent;
        }
        this.client = new FriendicaAPI.Client(baseUrl, token, agent);
        this.baseUrl = baseUrl;
    }
    cancel() {
        return this.client.cancel();
    }
    async registerApp(client_name, options) {
        const scopes = options.scopes || DEFAULT_SCOPE;
        return this.createApp(client_name, options).then(async (appData) => {
            return this.generateAuthUrl(appData.client_id, appData.client_secret, {
                scope: scopes,
                redirect_uri: appData.redirect_uri
            }).then(url => {
                appData.url = url;
                return appData;
            });
        });
    }
    async createApp(client_name, options) {
        const scopes = options.scopes || DEFAULT_SCOPE;
        const redirect_uris = options.redirect_uris || NO_REDIRECT;
        const params = {
            client_name: client_name,
            redirect_uris: redirect_uris,
            scopes: scopes.join(' ')
        };
        if (options.website)
            params.website = options.website;
        return this.client
            .post('/api/v1/apps', params)
            .then((res) => FriendicaOAuth.toAppData(res.data));
    }
    generateAuthUrl(clientId, clientSecret, options) {
        const scope = options.scope || DEFAULT_SCOPE;
        const redirect_uri = options.redirect_uri || NO_REDIRECT;
        return new Promise(resolve => {
            const oauthClient = new OAuth2Client({
                server: this.baseUrl,
                clientId: clientId,
                clientSecret: clientSecret,
                tokenEndpoint: '/oauth/token',
                authorizationEndpoint: '/oauth/authorize'
            });
            const url = oauthClient.authorizationCode.getAuthorizeUri({
                redirectUri: redirect_uri,
                scope: scope
            });
            resolve(url);
        });
    }
    verifyAppCredentials() {
        return this.client.get('/api/v1/apps/verify_credentials');
    }
    async fetchAccessToken(client_id, client_secret, code, redirect_uri = NO_REDIRECT) {
        if (!client_id) {
            throw new Error('client_id is required');
        }
        return this.client
            .post('/oauth/token', {
            client_id,
            client_secret,
            code,
            redirect_uri,
            grant_type: 'authorization_code'
        })
            .then((res) => FriendicaOAuth.toTokenData(res.data));
    }
    async refreshToken(client_id, client_secret, refresh_token) {
        return this.client
            .post('/oauth/token', {
            client_id,
            client_secret,
            refresh_token,
            grant_type: 'refresh_token'
        })
            .then((res) => FriendicaOAuth.toTokenData(res.data));
    }
    async revokeToken(client_id, client_secret, token) {
        return this.client.post('/oauth/revoke', {
            client_id,
            client_secret,
            token
        });
    }
    async registerAccount(_username, _email, _password, _agreement, _locale, _reason) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async verifyAccountCredentials() {
        return this.client.get('/api/v1/accounts/verify_credentials').then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.account(res.data)
            });
        });
    }
    async updateCredentials(_options) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getAccount(id) {
        return this.client.get(`/api/v1/accounts/${id}`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.account(res.data)
            });
        });
    }
    async getAccountStatuses(id, options) {
        let params = {};
        if (options) {
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.pinned) {
                params = Object.assign(params, {
                    pinned: options.pinned
                });
            }
            if (options.exclude_replies) {
                params = Object.assign(params, {
                    exclude_replies: options.exclude_replies
                });
            }
            if (options.exclude_reblogs) {
                params = Object.assign(params, {
                    exclude_reblogs: options.exclude_reblogs
                });
            }
            if (options.only_media) {
                params = Object.assign(params, {
                    only_media: options.only_media
                });
            }
        }
        return this.client.get(`/api/v1/accounts/${id}/statuses`, params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async subscribeAccount(id) {
        const params = {
            notify: true
        };
        return this.client.post(`/api/v1/accounts/${id}/follow`, params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async unsubscribeAccount(id) {
        const params = {
            notify: false
        };
        return this.client.post(`/api/v1/accounts/${id}/follow`, params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    getAccountFavourites(_id, _options) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getAccountFollowers(id, options) {
        let params = {};
        if (options) {
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.urlToAccounts(`/api/v1/accounts/${id}/followers`, params, options?.get_all || false, options?.sleep_ms || 0);
    }
    async getAccountFollowing(id, options) {
        let params = {};
        if (options) {
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.urlToAccounts(`/api/v1/accounts/${id}/following`, params, options?.get_all || false, options?.sleep_ms || 0);
    }
    async urlToAccounts(url, params, get_all, sleep_ms) {
        const res = await this.client.get(url, params);
        let converted = Object.assign({}, res, {
            data: res.data.map(a => FriendicaAPI.Converter.account(a))
        });
        if (get_all && converted.headers.link) {
            let parsed = parseLinkHeader(converted.headers.link);
            while (parsed['next']) {
                const nextRes = await this.client.get(parsed['next'], undefined, undefined, true);
                converted = Object.assign({}, converted, {
                    data: [...converted.data, ...nextRes.data.map(a => FriendicaAPI.Converter.account(a))]
                });
                if (nextRes.headers.link === undefined) {
                    break;
                }
                parsed = parseLinkHeader(nextRes.headers.link);
                if (sleep_ms) {
                    await new Promise(converted => setTimeout(converted, sleep_ms));
                }
            }
        }
        return converted;
    }
    async getAccountLists(id) {
        return this.client.get(`/api/v1/accounts/${id}/lists`).then(res => {
            return Object.assign(res, {
                data: res.data.map(l => FriendicaAPI.Converter.list(l))
            });
        });
    }
    async getIdentityProof(id) {
        return this.client.get(`/api/v1/accounts/${id}/identity_proofs`).then(res => {
            return Object.assign(res, {
                data: res.data.map(i => FriendicaAPI.Converter.identity_proof(i))
            });
        });
    }
    async followAccount(id, options) {
        let params = {};
        if (options) {
            if (options.reblog !== undefined) {
                params = Object.assign(params, {
                    reblog: options.reblog
                });
            }
        }
        return this.client.post(`/api/v1/accounts/${id}/follow`, params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async unfollowAccount(id) {
        return this.client.post(`/api/v1/accounts/${id}/unfollow`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async blockAccount(id) {
        return this.client.post(`/api/v1/accounts/${id}/block`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async unblockAccount(id) {
        return this.client.post(`/api/v1/accounts/${id}/unblock`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async muteAccount(id, notifications = true) {
        return this.client
            .post(`/api/v1/accounts/${id}/mute`, {
            notifications: notifications
        })
            .then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async unmuteAccount(id) {
        return this.client.post(`/api/v1/accounts/${id}/unmute`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async pinAccount(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async unpinAccount(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async setAccountNote(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getRelationship(id) {
        return this.client
            .get('/api/v1/accounts/relationships', {
            id: [id]
        })
            .then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data[0])
            });
        });
    }
    async getRelationships(ids) {
        return this.client
            .get('/api/v1/accounts/relationships', {
            id: ids
        })
            .then(res => {
            return Object.assign(res, {
                data: res.data.map(r => FriendicaAPI.Converter.relationship(r))
            });
        });
    }
    async searchAccount(q, options) {
        let params = { q: q };
        if (options) {
            if (options.following !== undefined && options.following !== null) {
                params = Object.assign(params, {
                    following: options.following
                });
            }
            if (options.resolve !== undefined && options.resolve !== null) {
                params = Object.assign(params, {
                    resolve: options.resolve
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/accounts/search', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    async lookupAccount(_acct) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getBookmarks(options) {
        let params = {};
        if (options) {
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
        }
        return this.client.get('/api/v1/bookmarks', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async getFavourites(options) {
        let params = {};
        if (options) {
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/favourites', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async getMutes(options) {
        let params = {};
        if (options) {
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/mutes', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    async getBlocks(options) {
        let params = {};
        if (options) {
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/blocks', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    async getDomainBlocks(_options) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    blockDomain(_domain) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    unblockDomain(_domain) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getFilters() {
        return this.client.get('/api/v1/filters').then(res => {
            return Object.assign(res, {
                data: res.data.map(f => FriendicaAPI.Converter.filter(f))
            });
        });
    }
    async getFilter(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async createFilter(_phrase, _context, _options) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async updateFilter(_id, _phrase, _context, _options) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async deleteFilter(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async report(_account_id, _options) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getFollowRequests(limit) {
        if (limit) {
            return this.client
                .get('/api/v1/follow_requests', {
                limit: limit
            })
                .then(res => {
                return Object.assign(res, {
                    data: res.data.map(a => FriendicaAPI.Converter.follow_request(a))
                });
            });
        }
        else {
            return this.client.get('/api/v1/follow_requests').then(res => {
                return Object.assign(res, {
                    data: res.data.map(a => FriendicaAPI.Converter.follow_request(a))
                });
            });
        }
    }
    async acceptFollowRequest(id) {
        return this.client.post(`/api/v1/follow_requests/${id}/authorize`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async rejectFollowRequest(id) {
        return this.client.post(`/api/v1/follow_requests/${id}/reject`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.relationship(res.data)
            });
        });
    }
    async getEndorsements(options) {
        let params = {};
        if (options) {
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
        }
        return this.client.get('/api/v1/endorsements', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    async getFeaturedTags() {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async createFeaturedTag(_name) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    deleteFeaturedTag(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getSuggestedTags() {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getPreferences() {
        return this.client.get('/api/v1/preferences').then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.preferences(res.data)
            });
        });
    }
    async getFollowedTags() {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getSuggestions(limit) {
        if (limit) {
            return this.client
                .get('/api/v1/suggestions', {
                limit: limit
            })
                .then(res => {
                return Object.assign(res, {
                    data: res.data.map(a => FriendicaAPI.Converter.account(a))
                });
            });
        }
        else {
            return this.client.get('/api/v1/suggestions').then(res => {
                return Object.assign(res, {
                    data: res.data.map(a => FriendicaAPI.Converter.account(a))
                });
            });
        }
    }
    async getTag(id) {
        return this.client.get(`/api/v1/tags/${id}`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.tag(res.data)
            });
        });
    }
    async followTag(id) {
        return this.client.post(`/api/v1/tags/${id}/follow`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.tag(res.data)
            });
        });
    }
    async unfollowTag(id) {
        return this.client.post(`/api/v1/tags/${id}/unfollow`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.tag(res.data)
            });
        });
    }
    async postStatus(status, options) {
        let params = {
            status: status
        };
        if (options) {
            if (options.media_ids) {
                params = Object.assign(params, {
                    media_ids: options.media_ids
                });
            }
            if (options.poll) {
                let pollParam = {
                    options: options.poll.options,
                    expires_in: options.poll.expires_in
                };
                if (options.poll.multiple !== undefined) {
                    pollParam = Object.assign(pollParam, {
                        multiple: options.poll.multiple
                    });
                }
                if (options.poll.hide_totals !== undefined) {
                    pollParam = Object.assign(pollParam, {
                        hide_totals: options.poll.hide_totals
                    });
                }
                params = Object.assign(params, {
                    poll: pollParam
                });
            }
            if (options.in_reply_to_id) {
                params = Object.assign(params, {
                    in_reply_to_id: options.in_reply_to_id
                });
            }
            if (options.sensitive !== undefined) {
                params = Object.assign(params, {
                    sensitive: options.sensitive
                });
            }
            if (options.spoiler_text) {
                params = Object.assign(params, {
                    spoiler_text: options.spoiler_text
                });
            }
            if (options.visibility) {
                params = Object.assign(params, {
                    visibility: FriendicaAPI.Converter.encodeVisibility(options.visibility)
                });
            }
            if (options.scheduled_at) {
                params = Object.assign(params, {
                    scheduled_at: options.scheduled_at
                });
            }
            if (options.language) {
                params = Object.assign(params, {
                    language: options.language
                });
            }
            if (options.quote_id) {
                params = Object.assign(params, {
                    quote_id: options.quote_id
                });
            }
        }
        if (options.scheduled_at) {
            return this.client.post('/api/v1/statuses', params).then(res => {
                return Object.assign(res, {
                    data: FriendicaAPI.Converter.scheduled_status(res.data)
                });
            });
        }
        return this.client.post('/api/v1/statuses', params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async getStatus(id) {
        return this.client.get(`/api/v1/statuses/${id}`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async editStatus(id, options) {
        let params = {};
        if (options.status) {
            params = Object.assign(params, {
                status: options.status
            });
        }
        if (options.spoiler_text) {
            params = Object.assign(params, {
                spoiler_text: options.spoiler_text
            });
        }
        if (options.sensitive) {
            params = Object.assign(params, {
                sensitive: options.sensitive
            });
        }
        if (options.media_ids) {
            params = Object.assign(params, {
                media_ids: options.media_ids
            });
        }
        if (options.poll) {
            let pollParam = {};
            if (options.poll.options !== undefined) {
                pollParam = Object.assign(pollParam, {
                    options: options.poll.options
                });
            }
            if (options.poll.expires_in !== undefined) {
                pollParam = Object.assign(pollParam, {
                    expires_in: options.poll.expires_in
                });
            }
            if (options.poll.multiple !== undefined) {
                pollParam = Object.assign(pollParam, {
                    multiple: options.poll.multiple
                });
            }
            if (options.poll.hide_totals !== undefined) {
                pollParam = Object.assign(pollParam, {
                    hide_totals: options.poll.hide_totals
                });
            }
            params = Object.assign(params, {
                poll: pollParam
            });
        }
        return this.client.put(`/api/v1/statuses/${id}`, params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async deleteStatus(id) {
        return this.client.del(`/api/v1/statuses/${id}`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async getStatusContext(id, options) {
        let params = {};
        if (options) {
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
        }
        return this.client.get(`/api/v1/statuses/${id}/context`, params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.context(res.data)
            });
        });
    }
    async getStatusSource(id) {
        return this.client.get(`/api/v1/statuses/${id}/source`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status_source(res.data)
            });
        });
    }
    async getStatusRebloggedBy(id) {
        return this.client.get(`/api/v1/statuses/${id}/reblogged_by`).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    async getStatusFavouritedBy(id) {
        return this.client.get(`/api/v1/statuses/${id}/favourited_by`).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    async favouriteStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/favourite`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async unfavouriteStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/unfavourite`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async reblogStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/reblog`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async unreblogStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/unreblog`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async bookmarkStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/bookmark`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async unbookmarkStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/unbookmark`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async muteStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/mute`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async unmuteStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/unmute`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async pinStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/pin`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async unpinStatus(id) {
        return this.client.post(`/api/v1/statuses/${id}/unpin`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.status(res.data)
            });
        });
    }
    async uploadMedia(file, options) {
        const formData = new FormData();
        formData.append('file', file);
        if (options) {
            if (options.description) {
                formData.append('description', options.description);
            }
            if (options.focus) {
                formData.append('focus', options.focus);
            }
        }
        return this.client.postForm('/api/v2/media', formData).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.async_attachment(res.data)
            });
        });
    }
    async getMedia(id) {
        const res = await this.client.get(`/api/v1/media/${id}`);
        return Object.assign(res, {
            data: FriendicaAPI.Converter.attachment(res.data)
        });
    }
    async updateMedia(id, options) {
        const formData = new FormData();
        if (options) {
            if (options.file) {
                formData.append('file', options.file);
            }
            if (options.description) {
                formData.append('description', options.description);
            }
            if (options.focus) {
                formData.append('focus', options.focus);
            }
        }
        return this.client.putForm(`/api/v1/media/${id}`, formData).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.attachment(res.data)
            });
        });
    }
    async getPoll(id) {
        return this.client.get(`/api/v1/polls/${id}`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.poll(res.data)
            });
        });
    }
    async votePoll(_id, _choices) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getScheduledStatuses(options) {
        let params = {};
        if (options) {
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
        }
        return this.client.get('/api/v1/scheduled_statuses', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.scheduled_status(s))
            });
        });
    }
    async getScheduledStatus(id) {
        return this.client.get(`/api/v1/scheduled_statuses/${id}`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.scheduled_status(res.data)
            });
        });
    }
    async scheduleStatus(_id, _scheduled_at) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    cancelScheduledStatus(id) {
        return this.client.del(`/api/v1/scheduled_statuses/${id}`);
    }
    async getPublicTimeline(options) {
        let params = {
            local: false
        };
        if (options) {
            if (options.only_media !== undefined) {
                params = Object.assign(params, {
                    only_media: options.only_media
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/timelines/public', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async getLocalTimeline(options) {
        let params = {
            local: true
        };
        if (options) {
            if (options.only_media !== undefined) {
                params = Object.assign(params, {
                    only_media: options.only_media
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/timelines/public', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async getTagTimeline(hashtag, options) {
        let params = {};
        if (options) {
            if (options.local !== undefined) {
                params = Object.assign(params, {
                    local: options.local
                });
            }
            if (options.only_media !== undefined) {
                params = Object.assign(params, {
                    only_media: options.only_media
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get(`/api/v1/timelines/tag/${hashtag}`, params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async getHomeTimeline(options) {
        let params = {};
        if (options) {
            if (options.local !== undefined) {
                params = Object.assign(params, {
                    local: options.local
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/timelines/home', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async getListTimeline(list_id, options) {
        let params = {};
        if (options) {
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get(`/api/v1/timelines/list/${list_id}`, params).then(res => {
            return Object.assign(res, {
                data: res.data.map(s => FriendicaAPI.Converter.status(s))
            });
        });
    }
    async getConversationTimeline(options) {
        let params = {};
        if (options) {
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
        }
        return this.client.get('/api/v1/conversations', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(c => FriendicaAPI.Converter.conversation(c))
            });
        });
    }
    deleteConversation(id) {
        return this.client.del(`/api/v1/conversations/${id}`);
    }
    async readConversation(id) {
        return this.client.post(`/api/v1/conversations/${id}/read`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.conversation(res.data)
            });
        });
    }
    async getLists() {
        return this.client.get('/api/v1/lists').then(res => {
            return Object.assign(res, {
                data: res.data.map(l => FriendicaAPI.Converter.list(l))
            });
        });
    }
    async getList(id) {
        return this.client.get(`/api/v1/lists/${id}`).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.list(res.data)
            });
        });
    }
    async createList(title) {
        return this.client
            .post('/api/v1/lists', {
            title: title
        })
            .then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.list(res.data)
            });
        });
    }
    async updateList(id, title) {
        return this.client
            .put(`/api/v1/lists/${id}`, {
            title: title
        })
            .then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.list(res.data)
            });
        });
    }
    deleteList(id) {
        return this.client.del(`/api/v1/lists/${id}`);
    }
    async getAccountsInList(id, options) {
        let params = {};
        if (options) {
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
        }
        return this.client.get(`/api/v1/lists/${id}/accounts`, params).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    addAccountsToList(id, account_ids) {
        return this.client.post(`/api/v1/lists/${id}/accounts`, {
            account_ids: account_ids
        });
    }
    deleteAccountsFromList(id, account_ids) {
        return this.client.del(`/api/v1/lists/${id}/accounts`, {
            account_ids: account_ids
        });
    }
    async getMarkers(_timeline) {
        return new Promise(resolve => {
            const res = {
                data: {},
                status: 200,
                statusText: '200',
                headers: {}
            };
            resolve(res);
        });
    }
    async saveMarkers(_options) {
        return new Promise(resolve => {
            const res = {
                data: {},
                status: 200,
                statusText: '200',
                headers: {}
            };
            resolve(res);
        });
    }
    async getNotifications(options) {
        let params = {};
        if (options) {
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.since_id) {
                params = Object.assign(params, {
                    since_id: options.since_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.exclude_types) {
                params = Object.assign(params, {
                    exclude_types: options.exclude_types.map(e => FriendicaAPI.Converter.encodeNotificationType(e))
                });
            }
            if (options.account_id) {
                params = Object.assign(params, {
                    account_id: options.account_id
                });
            }
        }
        return this.client.get('/api/v1/notifications', params).then(res => {
            return Object.assign(res, {
                data: res.data.flatMap(n => {
                    const notify = FriendicaAPI.Converter.notification(n);
                    if (notify instanceof UnknownNotificationTypeError)
                        return [];
                    return notify;
                })
            });
        });
    }
    async getNotification(id) {
        const res = await this.client.get(`/api/v1/notifications/${id}`);
        const notify = FriendicaAPI.Converter.notification(res.data);
        if (notify instanceof UnknownNotificationTypeError) {
            throw new UnknownNotificationTypeError();
        }
        return { ...res, data: notify };
    }
    dismissNotifications() {
        return this.client.post('/api/v1/notifications/clear');
    }
    dismissNotification(id) {
        return this.client.post(`/api/v1/notifications/${id}/dismiss`);
    }
    readNotifications(_options) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async subscribePushNotification(subscription, data) {
        let params = {
            subscription
        };
        if (data) {
            params = Object.assign(params, {
                data
            });
        }
        return this.client.post('/api/v1/push/subscription', params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.push_subscription(res.data)
            });
        });
    }
    async getPushSubscription() {
        return this.client.get('/api/v1/push/subscription').then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.push_subscription(res.data)
            });
        });
    }
    async updatePushSubscription(data) {
        let params = {};
        if (data) {
            params = Object.assign(params, {
                data
            });
        }
        return this.client.put('/api/v1/push/subscription', params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.push_subscription(res.data)
            });
        });
    }
    deletePushSubscription() {
        return this.client.del('/api/v1/push/subscription');
    }
    async search(q, options) {
        let params = {
            q
        };
        if (options) {
            if (options.type) {
                params = Object.assign(params, {
                    type: options.type
                });
            }
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.max_id) {
                params = Object.assign(params, {
                    max_id: options.max_id
                });
            }
            if (options.min_id) {
                params = Object.assign(params, {
                    min_id: options.min_id
                });
            }
            if (options.resolve !== undefined) {
                params = Object.assign(params, {
                    resolve: options.resolve
                });
            }
            if (options.offset) {
                params = Object.assign(params, {
                    offset: options.offset
                });
            }
            if (options.following !== undefined) {
                params = Object.assign(params, {
                    following: options.following
                });
            }
            if (options.account_id) {
                params = Object.assign(params, {
                    account_id: options.account_id
                });
            }
            if (options.exclude_unreviewed) {
                params = Object.assign(params, {
                    exclude_unreviewed: options.exclude_unreviewed
                });
            }
        }
        return this.client.get('/api/v2/search', params).then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.results(res.data)
            });
        });
    }
    async getInstance() {
        return this.client.get('/api/v1/instance').then(res => {
            return Object.assign(res, {
                data: FriendicaAPI.Converter.instance(res.data)
            });
        });
    }
    getInstancePeers() {
        return this.client.get('/api/v1/instance/peers');
    }
    async getInstanceActivity() {
        return this.client.get('/api/v1/instance/activity').then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.activity(a))
            });
        });
    }
    async getInstanceTrends(limit) {
        let params = {};
        if (limit) {
            params = Object.assign(params, {
                limit
            });
        }
        return this.client.get('/api/v1/trends', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(t => FriendicaAPI.Converter.tag(t))
            });
        });
    }
    async getInstanceDirectory(options) {
        let params = {};
        if (options) {
            if (options.limit) {
                params = Object.assign(params, {
                    limit: options.limit
                });
            }
            if (options.offset) {
                params = Object.assign(params, {
                    offset: options.offset
                });
            }
            if (options.order) {
                params = Object.assign(params, {
                    order: options.order
                });
            }
            if (options.local !== undefined) {
                params = Object.assign(params, {
                    local: options.local
                });
            }
        }
        return this.client.get('/api/v1/directory', params).then(res => {
            return Object.assign(res, {
                data: res.data.map(a => FriendicaAPI.Converter.account(a))
            });
        });
    }
    async getInstanceCustomEmojis() {
        return this.client.get('/api/v1/custom_emojis').then(res => {
            return Object.assign(res, {
                data: res.data.map(e => FriendicaAPI.Converter.emoji(e))
            });
        });
    }
    async getInstanceAnnouncements() {
        return new Promise(resolve => {
            resolve({
                data: [],
                status: 200,
                statusText: '200',
                headers: null
            });
        });
    }
    async dismissInstanceAnnouncement(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async addReactionToAnnouncement(_id, _name) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async removeReactionFromAnnouncement(_id, _name) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async createEmojiReaction(_id, _emoji) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async deleteEmojiReaction(_id, _emoji) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getEmojiReactions(_id) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async getEmojiReaction(_id, _emoji) {
        return new Promise((_, reject) => {
            const err = new NotImplementedError('Friendica does not support this method');
            reject(err);
        });
    }
    async streamingURL() {
        const instance = await this.getInstance();
        if (instance.data.urls) {
            return instance.data.urls.streaming_api;
        }
        return this.baseUrl;
    }
    async userStreaming() {
        const url = await this.streamingURL();
        return this.client.socket(`${url}/api/v1/streaming`, 'user');
    }
    async publicStreaming() {
        const url = await this.streamingURL();
        return this.client.socket(`${url}/api/v1/streaming`, 'public');
    }
    async localStreaming() {
        const url = await this.streamingURL();
        return this.client.socket(`${url}/api/v1/streaming`, 'public:local');
    }
    async tagStreaming(tag) {
        const url = await this.streamingURL();
        return this.client.socket(`${url}/api/v1/streaming`, 'hashtag', `tag=${tag}`);
    }
    async listStreaming(list_id) {
        const url = await this.streamingURL();
        return this.client.socket(`${url}/api/v1/streaming`, 'list', `list=${list_id}`);
    }
    async directStreaming() {
        const url = await this.streamingURL();
        return this.client.socket(`${url}/api/v1/streaming`, 'direct');
    }
}