From 8958bd1b6e1f84e93c6f9a5f083f22365f7eef5b Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sun, 2 Jul 2023 18:34:30 +0200 Subject: [PATCH] Remove mastodon and pleroma backend support --- megalodon/src/index.ts | 4 - megalodon/src/mastodon.ts | 2309 ---------------- megalodon/src/mastodon/api_client.ts | 650 ----- megalodon/src/mastodon/entities/account.ts | 27 - megalodon/src/mastodon/entities/activity.ts | 8 - .../src/mastodon/entities/announcement.ts | 41 - .../src/mastodon/entities/application.ts | 7 - .../src/mastodon/entities/async_attachment.ts | 14 - megalodon/src/mastodon/entities/attachment.ts | 49 - megalodon/src/mastodon/entities/card.ts | 16 - megalodon/src/mastodon/entities/context.ts | 8 - .../src/mastodon/entities/conversation.ts | 11 - megalodon/src/mastodon/entities/emoji.ts | 9 - .../src/mastodon/entities/featured_tag.ts | 8 - megalodon/src/mastodon/entities/field.ts | 7 - megalodon/src/mastodon/entities/filter.ts | 12 - megalodon/src/mastodon/entities/history.ts | 7 - .../src/mastodon/entities/identity_proof.ts | 9 - megalodon/src/mastodon/entities/instance.ts | 41 - megalodon/src/mastodon/entities/list.ts | 6 - megalodon/src/mastodon/entities/marker.ts | 14 - megalodon/src/mastodon/entities/mention.ts | 8 - .../src/mastodon/entities/notification.ts | 14 - megalodon/src/mastodon/entities/poll.ts | 13 - .../src/mastodon/entities/poll_option.ts | 6 - .../src/mastodon/entities/preferences.ts | 9 - .../mastodon/entities/push_subscription.ts | 16 - .../src/mastodon/entities/relationship.ts | 18 - megalodon/src/mastodon/entities/report.ts | 9 - megalodon/src/mastodon/entities/results.ts | 11 - .../src/mastodon/entities/scheduled_status.ts | 10 - megalodon/src/mastodon/entities/source.ts | 10 - megalodon/src/mastodon/entities/stats.ts | 7 - megalodon/src/mastodon/entities/status.ts | 44 - .../src/mastodon/entities/status_params.ts | 12 - megalodon/src/mastodon/entities/tag.ts | 10 - megalodon/src/mastodon/entities/token.ts | 8 - megalodon/src/mastodon/entities/urls.ts | 5 - megalodon/src/mastodon/entity.ts | 37 - megalodon/src/mastodon/notification.ts | 13 - megalodon/src/mastodon/web_socket.ts | 342 --- megalodon/src/megalodon.ts | 21 +- megalodon/src/pleroma.ts | 2344 ----------------- megalodon/src/pleroma/api_client.ts | 670 ----- megalodon/src/pleroma/entities/account.ts | 27 - megalodon/src/pleroma/entities/activity.ts | 8 - .../src/pleroma/entities/announcement.ts | 34 - megalodon/src/pleroma/entities/application.ts | 7 - .../src/pleroma/entities/async_attachment.ts | 14 - megalodon/src/pleroma/entities/attachment.ts | 49 - megalodon/src/pleroma/entities/card.ts | 17 - megalodon/src/pleroma/entities/context.ts | 8 - .../src/pleroma/entities/conversation.ts | 11 - megalodon/src/pleroma/entities/emoji.ts | 9 - .../src/pleroma/entities/featured_tag.ts | 8 - megalodon/src/pleroma/entities/field.ts | 7 - megalodon/src/pleroma/entities/filter.ts | 12 - megalodon/src/pleroma/entities/history.ts | 7 - .../src/pleroma/entities/identity_proof.ts | 9 - megalodon/src/pleroma/entities/instance.ts | 41 - megalodon/src/pleroma/entities/list.ts | 6 - megalodon/src/pleroma/entities/marker.ts | 12 - megalodon/src/pleroma/entities/mention.ts | 8 - .../src/pleroma/entities/notification.ts | 15 - megalodon/src/pleroma/entities/poll.ts | 13 - megalodon/src/pleroma/entities/poll_option.ts | 6 - megalodon/src/pleroma/entities/preferences.ts | 9 - .../src/pleroma/entities/push_subscription.ts | 16 - megalodon/src/pleroma/entities/reaction.ts | 10 - .../src/pleroma/entities/relationship.ts | 16 - megalodon/src/pleroma/entities/report.ts | 9 - megalodon/src/pleroma/entities/results.ts | 11 - .../src/pleroma/entities/scheduled_status.ts | 10 - megalodon/src/pleroma/entities/source.ts | 10 - megalodon/src/pleroma/entities/stats.ts | 7 - megalodon/src/pleroma/entities/status.ts | 60 - .../src/pleroma/entities/status_params.ts | 12 - megalodon/src/pleroma/entities/tag.ts | 10 - megalodon/src/pleroma/entities/token.ts | 8 - megalodon/src/pleroma/entities/urls.ts | 5 - megalodon/src/pleroma/entity.ts | 38 - megalodon/src/pleroma/notification.ts | 13 - megalodon/src/pleroma/web_socket.ts | 343 --- megalodon/test/integration/cancel.spec.ts | 38 - megalodon/test/integration/cancelWorker.ts | 5 - megalodon/test/integration/mastodon.spec.ts | 182 -- .../integration/mastodon/api_client.spec.ts | 161 -- megalodon/test/integration/pleroma.spec.ts | 187 -- megalodon/test/unit/mastodon.spec.ts | 6 - .../test/unit/mastodon/api_client.spec.ts | 80 - .../test/unit/pleroma/api_client.spec.ts | 200 -- megalodon/test/unit/webo_socket.spec.ts | 180 -- 92 files changed, 1 insertion(+), 8847 deletions(-) delete mode 100644 megalodon/src/mastodon.ts delete mode 100644 megalodon/src/mastodon/api_client.ts delete mode 100644 megalodon/src/mastodon/entities/account.ts delete mode 100644 megalodon/src/mastodon/entities/activity.ts delete mode 100644 megalodon/src/mastodon/entities/announcement.ts delete mode 100644 megalodon/src/mastodon/entities/application.ts delete mode 100644 megalodon/src/mastodon/entities/async_attachment.ts delete mode 100644 megalodon/src/mastodon/entities/attachment.ts delete mode 100644 megalodon/src/mastodon/entities/card.ts delete mode 100644 megalodon/src/mastodon/entities/context.ts delete mode 100644 megalodon/src/mastodon/entities/conversation.ts delete mode 100644 megalodon/src/mastodon/entities/emoji.ts delete mode 100644 megalodon/src/mastodon/entities/featured_tag.ts delete mode 100644 megalodon/src/mastodon/entities/field.ts delete mode 100644 megalodon/src/mastodon/entities/filter.ts delete mode 100644 megalodon/src/mastodon/entities/history.ts delete mode 100644 megalodon/src/mastodon/entities/identity_proof.ts delete mode 100644 megalodon/src/mastodon/entities/instance.ts delete mode 100644 megalodon/src/mastodon/entities/list.ts delete mode 100644 megalodon/src/mastodon/entities/marker.ts delete mode 100644 megalodon/src/mastodon/entities/mention.ts delete mode 100644 megalodon/src/mastodon/entities/notification.ts delete mode 100644 megalodon/src/mastodon/entities/poll.ts delete mode 100644 megalodon/src/mastodon/entities/poll_option.ts delete mode 100644 megalodon/src/mastodon/entities/preferences.ts delete mode 100644 megalodon/src/mastodon/entities/push_subscription.ts delete mode 100644 megalodon/src/mastodon/entities/relationship.ts delete mode 100644 megalodon/src/mastodon/entities/report.ts delete mode 100644 megalodon/src/mastodon/entities/results.ts delete mode 100644 megalodon/src/mastodon/entities/scheduled_status.ts delete mode 100644 megalodon/src/mastodon/entities/source.ts delete mode 100644 megalodon/src/mastodon/entities/stats.ts delete mode 100644 megalodon/src/mastodon/entities/status.ts delete mode 100644 megalodon/src/mastodon/entities/status_params.ts delete mode 100644 megalodon/src/mastodon/entities/tag.ts delete mode 100644 megalodon/src/mastodon/entities/token.ts delete mode 100644 megalodon/src/mastodon/entities/urls.ts delete mode 100644 megalodon/src/mastodon/entity.ts delete mode 100644 megalodon/src/mastodon/notification.ts delete mode 100644 megalodon/src/mastodon/web_socket.ts delete mode 100644 megalodon/src/pleroma.ts delete mode 100644 megalodon/src/pleroma/api_client.ts delete mode 100644 megalodon/src/pleroma/entities/account.ts delete mode 100644 megalodon/src/pleroma/entities/activity.ts delete mode 100644 megalodon/src/pleroma/entities/announcement.ts delete mode 100644 megalodon/src/pleroma/entities/application.ts delete mode 100644 megalodon/src/pleroma/entities/async_attachment.ts delete mode 100644 megalodon/src/pleroma/entities/attachment.ts delete mode 100644 megalodon/src/pleroma/entities/card.ts delete mode 100644 megalodon/src/pleroma/entities/context.ts delete mode 100644 megalodon/src/pleroma/entities/conversation.ts delete mode 100644 megalodon/src/pleroma/entities/emoji.ts delete mode 100644 megalodon/src/pleroma/entities/featured_tag.ts delete mode 100644 megalodon/src/pleroma/entities/field.ts delete mode 100644 megalodon/src/pleroma/entities/filter.ts delete mode 100644 megalodon/src/pleroma/entities/history.ts delete mode 100644 megalodon/src/pleroma/entities/identity_proof.ts delete mode 100644 megalodon/src/pleroma/entities/instance.ts delete mode 100644 megalodon/src/pleroma/entities/list.ts delete mode 100644 megalodon/src/pleroma/entities/marker.ts delete mode 100644 megalodon/src/pleroma/entities/mention.ts delete mode 100644 megalodon/src/pleroma/entities/notification.ts delete mode 100644 megalodon/src/pleroma/entities/poll.ts delete mode 100644 megalodon/src/pleroma/entities/poll_option.ts delete mode 100644 megalodon/src/pleroma/entities/preferences.ts delete mode 100644 megalodon/src/pleroma/entities/push_subscription.ts delete mode 100644 megalodon/src/pleroma/entities/reaction.ts delete mode 100644 megalodon/src/pleroma/entities/relationship.ts delete mode 100644 megalodon/src/pleroma/entities/report.ts delete mode 100644 megalodon/src/pleroma/entities/results.ts delete mode 100644 megalodon/src/pleroma/entities/scheduled_status.ts delete mode 100644 megalodon/src/pleroma/entities/source.ts delete mode 100644 megalodon/src/pleroma/entities/stats.ts delete mode 100644 megalodon/src/pleroma/entities/status.ts delete mode 100644 megalodon/src/pleroma/entities/status_params.ts delete mode 100644 megalodon/src/pleroma/entities/tag.ts delete mode 100644 megalodon/src/pleroma/entities/token.ts delete mode 100644 megalodon/src/pleroma/entities/urls.ts delete mode 100644 megalodon/src/pleroma/entity.ts delete mode 100644 megalodon/src/pleroma/notification.ts delete mode 100644 megalodon/src/pleroma/web_socket.ts delete mode 100644 megalodon/test/integration/cancel.spec.ts delete mode 100644 megalodon/test/integration/cancelWorker.ts delete mode 100644 megalodon/test/integration/mastodon.spec.ts delete mode 100644 megalodon/test/integration/mastodon/api_client.spec.ts delete mode 100644 megalodon/test/integration/pleroma.spec.ts delete mode 100644 megalodon/test/unit/mastodon.spec.ts delete mode 100644 megalodon/test/unit/mastodon/api_client.spec.ts delete mode 100644 megalodon/test/unit/pleroma/api_client.spec.ts delete mode 100644 megalodon/test/unit/webo_socket.spec.ts diff --git a/megalodon/src/index.ts b/megalodon/src/index.ts index d6fd9b6..15486ad 100644 --- a/megalodon/src/index.ts +++ b/megalodon/src/index.ts @@ -3,8 +3,6 @@ import OAuth from './oauth' import { isCancel, RequestCanceledError } from './cancel' import { ProxyConfig } from './proxy_config' import generator, { detector, MegalodonInterface, WebSocketInterface } from './megalodon' -import Mastodon from './mastodon' -import Pleroma from './pleroma' import Misskey from './misskey' import Entity from './entity' import NotificationType from './notification' @@ -22,8 +20,6 @@ export { WebSocketInterface, NotificationType, FilterContext, - Mastodon, - Pleroma, Misskey, Entity, Converter diff --git a/megalodon/src/mastodon.ts b/megalodon/src/mastodon.ts deleted file mode 100644 index 56686a4..0000000 --- a/megalodon/src/mastodon.ts +++ /dev/null @@ -1,2309 +0,0 @@ -import { OAuth2 } from 'oauth' -import FormData from 'form-data' -import parseLinkHeader from 'parse-link-header' - -import MastodonAPI from './mastodon/api_client' -import WebSocket from './mastodon/web_socket' -import { MegalodonInterface, NoImplementedError } from './megalodon' -import Response from './response' -import Entity from './entity' -import { NO_REDIRECT, DEFAULT_SCOPE, DEFAULT_UA } from './default' -import { ProxyConfig } from './proxy_config' -import OAuth from './oauth' - -export default class Mastodon implements MegalodonInterface { - public client: MastodonAPI.Interface - public baseUrl: string - - /** - * @param baseUrl hostname or base URL - * @param accessToken access token from OAuth2 authorization - * @param userAgent UserAgent is specified in header on request. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor( - baseUrl: string, - accessToken: string | null = null, - userAgent: string | null = DEFAULT_UA, - proxyConfig: ProxyConfig | false = false - ) { - let token: string = '' - if (accessToken) { - token = accessToken - } - let agent: string = DEFAULT_UA - if (userAgent) { - agent = userAgent - } - this.client = new MastodonAPI.Client(baseUrl, token, agent, proxyConfig) - this.baseUrl = baseUrl - } - - public cancel(): void { - return this.client.cancel() - } - - public async registerApp( - client_name: string, - options: Partial<{ scopes: Array; redirect_uris: string; website: string }> - ): Promise { - 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 - }) - }) - } - - /** - * Call /api/v1/apps - * - * Create an application. - * @param client_name your application's name - * @param options Form Data - */ - public async createApp( - client_name: string, - options: Partial<{ scopes: Array; redirect_uris: string; website: string }> - ): Promise { - const scopes = options.scopes || DEFAULT_SCOPE - const redirect_uris = options.redirect_uris || NO_REDIRECT - - const params: { - client_name: string - redirect_uris: string - scopes: string - website?: string - } = { - 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: Response) => OAuth.AppData.from(res.data)) - } - - /** - * Generate authorization url using OAuth2. - * - * @param clientId your OAuth app's client ID - * @param clientSecret your OAuth app's client Secret - * @param options as property, redirect_uri and scope are available, and must be the same as when you register your app - */ - public generateAuthUrl( - clientId: string, - clientSecret: string, - options: Partial<{ scope: Array; redirect_uri: string }> - ): Promise { - const scope = options.scope || DEFAULT_SCOPE - const redirect_uri = options.redirect_uri || NO_REDIRECT - return new Promise(resolve => { - const oauth = new OAuth2(clientId, clientSecret, this.baseUrl, undefined, '/oauth/token') - const url = oauth.getAuthorizeUrl({ - redirect_uri: redirect_uri, - response_type: 'code', - client_id: clientId, - scope: scope.join(' ') - }) - resolve(url) - }) - } - - // ====================================== - // apps - // ====================================== - public verifyAppCredentials(): Promise> { - return this.client.get('/api/v1/apps/verify_credentials') - } - - // ====================================== - // apps/oauth - // ====================================== - public async fetchAccessToken( - client_id: string | null, - client_secret: string, - code: string, - redirect_uri: string = NO_REDIRECT - ): Promise { - 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: Response) => OAuth.TokenData.from(res.data)) - } - - public async refreshToken(client_id: string, client_secret: string, refresh_token: string): Promise { - return this.client - .post('/oauth/token', { - client_id, - client_secret, - refresh_token, - grant_type: 'refresh_token' - }) - .then((res: Response) => OAuth.TokenData.from(res.data)) - } - - public async revokeToken(client_id: string, client_secret: string, token: string): Promise> { - return this.client.post<{}>('/oauth/revoke', { - client_id, - client_secret, - token - }) - } - - // ====================================== - // accounts - // ====================================== - public async registerAccount( - username: string, - email: string, - password: string, - agreement: boolean, - locale: string, - reason?: string | null - ): Promise> { - let params = { - username: username, - email: email, - password: password, - agreement: agreement, - locale: locale - } - if (reason) { - params = Object.assign(params, { - reason: reason - }) - } - return this.client.post('/api/v1/accounts', params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.token(res.data) - }) - }) - } - - public async verifyAccountCredentials(): Promise> { - return this.client.get('/api/v1/accounts/verify_credentials').then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.account(res.data) - }) - }) - } - - public async updateCredentials(options?: { - discoverable?: boolean - bot?: boolean - display_name?: string - note?: string - avatar?: string - header?: string - locked?: boolean - source?: { - privacy?: string - sensitive?: boolean - language?: string - } - fields_attributes?: Array<{ name: string; value: string }> - }): Promise> { - let params = {} - if (options) { - if (options.discoverable !== undefined) { - params = Object.assign(params, { - discoverable: options.discoverable - }) - } - if (options.bot !== undefined) { - params = Object.assign(params, { - bot: options.bot - }) - } - if (options.display_name) { - params = Object.assign(params, { - display_name: options.display_name - }) - } - if (options.note) { - params = Object.assign(params, { - note: options.note - }) - } - if (options.avatar) { - params = Object.assign(params, { - avatar: options.avatar - }) - } - if (options.header) { - params = Object.assign(params, { - header: options.header - }) - } - if (options.locked !== undefined) { - params = Object.assign(params, { - locked: options.locked - }) - } - if (options.source) { - params = Object.assign(params, { - source: options.source - }) - } - if (options.fields_attributes) { - params = Object.assign(params, { - fields_attributes: options.fields_attributes - }) - } - } - return this.client.patch('/api/v1/accounts/update_credentials', params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.account(res.data) - }) - }) - } - - public async getAccount(id: string): Promise> { - return this.client.get(`/api/v1/accounts/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.account(res.data) - }) - }) - } - - public async getAccountStatuses( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - pinned?: boolean - exclude_replies?: boolean - exclude_reblogs?: boolean - only_media: boolean - } - ): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - public async subscribeAccount(id: string): Promise> { - const params = { - notify: true - } - return this.client.post(`/api/v1/accounts/${id}/follow`, params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async unsubscribeAccount(id: string): Promise> { - const params = { - notify: false - } - return this.client.post(`/api/v1/accounts/${id}/follow`, params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public getAccountFavourites( - _id: string, - _options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('mastodon does not support') - reject(err) - }) - } - - public async getAccountFollowers( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - get_all?: boolean - sleep_ms?: number - } - ): Promise>> { - 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) - } - - public async getAccountFollowing( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - get_all?: boolean - sleep_ms?: number - } - ): Promise>> { - 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) - } - - /** Helper function to optionally follow Link headers as pagination */ - private async urlToAccounts(url: string, params: Record, get_all: boolean, sleep_ms: number) { - const res = await this.client.get>(url, params) - res.data = res.data.map(a => MastodonAPI.Converter.account(a)) - if (get_all && res.headers.link) { - let parsed = parseLinkHeader(res.headers.link) - while (parsed?.next) { - const nextRes = await this.client.get>(parsed?.next.url, undefined, undefined, true) - res.data.push(...nextRes.data.map(a => MastodonAPI.Converter.account(a))) - parsed = parseLinkHeader(nextRes.headers.link) - if (sleep_ms) { - await new Promise(res => setTimeout(res, sleep_ms)) - } - } - } - return res - } - - public async getAccountLists(id: string): Promise>> { - return this.client.get>(`/api/v1/accounts/${id}/lists`).then(res => { - return Object.assign(res, { - data: res.data.map(l => MastodonAPI.Converter.list(l)) - }) - }) - } - - public async getIdentityProof(id: string): Promise>> { - return this.client.get>(`/api/v1/accounts/${id}/identity_proofs`).then(res => { - return Object.assign(res, { - data: res.data.map(i => MastodonAPI.Converter.identity_proof(i)) - }) - }) - } - - public async followAccount(id: string, options?: { reblog?: boolean }): Promise> { - 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: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async unfollowAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unfollow`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async blockAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/block`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async unblockAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unblock`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async muteAccount(id: string, notifications: boolean = true): Promise> { - return this.client - .post(`/api/v1/accounts/${id}/mute`, { - notifications: notifications - }) - .then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async unmuteAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unmute`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async pinAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/pin`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async unpinAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unpin`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async getRelationship(id: string): Promise> { - return this.client - .get>('/api/v1/accounts/relationships', { - id: [id] - }) - .then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data[0]) - }) - }) - } - - public async getRelationships(ids: Array): Promise>> { - return this.client - .get>('/api/v1/accounts/relationships', { - id: ids - }) - .then(res => { - return Object.assign(res, { - data: res.data.map(r => MastodonAPI.Converter.relationship(r)) - }) - }) - } - - public async searchAccount( - q: string, - options?: { - following?: boolean - resolve?: boolean - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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 => MastodonAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/bookmarks - // ====================================== - - public async getBookmarks(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - // ====================================== - // accounts/favourites - // ====================================== - - public async getFavourites(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - // ====================================== - // accounts/mutes - // ====================================== - - public async getMutes(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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 => MastodonAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/blocks - // ====================================== - - public async getBlocks(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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 => MastodonAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/domain_blocks - // ====================================== - public async getDomainBlocks(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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/domain_blocks', params) - } - - public blockDomain(domain: string): Promise> { - return this.client.post<{}>('/api/v1/domain_blocks', { - domain: domain - }) - } - - public unblockDomain(domain: string): Promise> { - return this.client.del<{}>('/api/v1/domain_blocks', { - domain: domain - }) - } - - // ====================================== - // accounts/filters - // ====================================== - - public async getFilters(): Promise>> { - return this.client.get>('/api/v1/filters').then(res => { - return Object.assign(res, { - data: res.data.map(f => MastodonAPI.Converter.filter(f)) - }) - }) - } - - public async getFilter(id: string): Promise> { - return this.client.get(`/api/v1/filters/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.filter(res.data) - }) - }) - } - - public async createFilter( - phrase: string, - context: Array, - options?: { - irreversible?: boolean - whole_word?: boolean - expires_in?: string - } - ): Promise> { - let params = { - phrase: phrase, - context: context - } - if (options) { - if (options.irreversible !== undefined) { - params = Object.assign(params, { - irreversible: options.irreversible - }) - } - if (options.whole_word !== undefined) { - params = Object.assign(params, { - whole_word: options.whole_word - }) - } - if (options.expires_in) { - params = Object.assign(params, { - expires_in: options.expires_in - }) - } - } - return this.client.post('/api/v1/filters', params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.filter(res.data) - }) - }) - } - - public async updateFilter( - id: string, - phrase: string, - context: Array, - options?: { - irreversible?: boolean - whole_word?: boolean - expires_in?: string - } - ): Promise> { - let params = { - phrase: phrase, - context: context - } - if (options) { - if (options.irreversible !== undefined) { - params = Object.assign(params, { - irreversible: options.irreversible - }) - } - if (options.whole_word !== undefined) { - params = Object.assign(params, { - whole_word: options.whole_word - }) - } - if (options.expires_in) { - params = Object.assign(params, { - expires_in: options.expires_in - }) - } - } - return this.client.put(`/api/v1/filters/${id}`, params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.filter(res.data) - }) - }) - } - - public async deleteFilter(id: string): Promise> { - return this.client.del(`/api/v1/filters/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.filter(res.data) - }) - }) - } - - // ====================================== - // accounts/reports - // ====================================== - public async report( - account_id: string, - comment: string, - options?: { - status_ids?: Array - - forward?: boolean - } - ): Promise> { - let params = { - account_id: account_id, - comment: comment - } - if (options) { - if (options.status_ids) { - params = Object.assign(params, { - status_ids: options.status_ids - }) - } - if (options.forward !== undefined) { - params = Object.assign(params, { - forward: options.forward - }) - } - } - return this.client.post('/api/v1/reports', params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.report(res.data) - }) - }) - } - - // ====================================== - // accounts/follow_requests - // ====================================== - public async getFollowRequests(limit?: number): Promise>> { - if (limit) { - return this.client - .get>('/api/v1/follow_requests', { - limit: limit - }) - .then(res => { - return Object.assign(res, { - data: res.data.map(a => MastodonAPI.Converter.account(a)) - }) - }) - } else { - return this.client.get>('/api/v1/follow_requests').then(res => { - return Object.assign(res, { - data: res.data.map(a => MastodonAPI.Converter.account(a)) - }) - }) - } - } - - public async acceptFollowRequest(id: string): Promise> { - return this.client.post(`/api/v1/follow_requests/${id}/authorize`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - public async rejectFollowRequest(id: string): Promise> { - return this.client.post(`/api/v1/follow_requests/${id}/reject`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.relationship(res.data) - }) - }) - } - - // ====================================== - // accounts/endorsements - // ====================================== - public async getEndorsements(options?: { limit?: number; max_id?: string; since_id?: string }): Promise>> { - 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 => MastodonAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/featured_tags - // ====================================== - public async getFeaturedTags(): Promise>> { - return this.client.get>('/api/v1/featured_tags').then(res => { - return Object.assign(res, { - data: res.data.map(f => MastodonAPI.Converter.featured_tag(f)) - }) - }) - } - - public async getAccountFeaturedTags(id :string): Promise>> { - return this.client.get>(`/api/v1/accounts/${id}/featured_tags`).then(res => { - return Object.assign(res, { - data: res.data.map(f => MastodonAPI.Converter.featured_tag(f)) - }) - }) - } - - public async createFeaturedTag(name: string): Promise> { - return this.client - .post('/api/v1/featured_tags', { - name: name - }) - .then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.featured_tag(res.data) - }) - }) - } - - public deleteFeaturedTag(id: string): Promise> { - return this.client.del<{}>(`/api/v1/featured_tags/${id}`) - } - - public async getSuggestedTags(): Promise>> { - return this.client.get>('/api/v1/featured_tags/suggestions').then(res => { - return Object.assign(res, { - data: res.data.map(t => MastodonAPI.Converter.tag(t)) - }) - }) - } - - // ====================================== - // accounts/preferences - // ====================================== - public async getPreferences(): Promise> { - return this.client.get('/api/v1/preferences').then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.preferences(res.data) - }) - }) - } - - // ====================================== - // accounts/suggestions - // ====================================== - public async getSuggestions(limit?: number): Promise>> { - if (limit) { - return this.client - .get>('/api/v1/suggestions', { - limit: limit - }) - .then(res => { - return Object.assign(res, { - data: res.data.map(a => MastodonAPI.Converter.account(a)) - }) - }) - } else { - return this.client.get>('/api/v1/suggestions').then(res => { - return Object.assign(res, { - data: res.data.map(a => MastodonAPI.Converter.account(a)) - }) - }) - } - } - - // ====================================== - // accounts/tags - // ====================================== - public async getTag(id: string): Promise> { - return this.client.get(`/api/v1/tags/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.tag(res.data) - }) - }) - } - - public async followTag(id: string): Promise> { - return this.client.post(`/api/v1/tags/${id}/follow`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.tag(res.data) - }) - }) - } - - public async unfollowTag(id: string): Promise> { - return this.client.post(`/api/v1/tags/${id}/unfollow`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.tag(res.data) - }) - }) - } - - // ====================================== - // statuses - // ====================================== - public async postStatus( - status: string, - options: { - media_ids?: Array - poll?: { options: Array; expires_in: number; multiple?: boolean; hide_totals?: boolean } - in_reply_to_id?: string - sensitive?: boolean - spoiler_text?: string - visibility?: 'public' | 'unlisted' | 'private' | 'direct' - scheduled_at?: string - language?: string - quote_id?: string - } - ): Promise> { - 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: 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 - }) - } - } - return this.client.post('/api/v1/statuses', params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async getStatus(id: string): Promise> { - return this.client.get(`/api/v1/statuses/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async editStatus( - id: string, - options: { - status?: string - spoiler_text?: string - sensitive?: boolean - media_ids?: Array - poll?: { options?: Array; expires_in?: number; multiple?: boolean; hide_totals?: boolean } - } - ): Promise> { - 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: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async deleteStatus(id: string): Promise> { - return this.client.del(`/api/v1/statuses/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async getStatusContext( - id: string, - options?: { limit?: number; max_id?: string; since_id?: string } - ): Promise> { - 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: MastodonAPI.Converter.context(res.data) - }) - }) - } - - public async getStatusRebloggedBy(id: string): Promise>> { - return this.client.get>(`/api/v1/statuses/${id}/reblogged_by`).then(res => { - return Object.assign(res, { - data: res.data.map(a => MastodonAPI.Converter.account(a)) - }) - }) - } - - public async getStatusFavouritedBy(id: string): Promise>> { - return this.client.get>(`/api/v1/statuses/${id}/favourited_by`).then(res => { - return Object.assign(res, { - data: res.data.map(a => MastodonAPI.Converter.account(a)) - }) - }) - } - - public async favouriteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/favourite`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async unfavouriteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unfavourite`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async reblogStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/reblog`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async unreblogStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unreblog`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async bookmarkStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/bookmark`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async unbookmarkStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unbookmark`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async muteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/mute`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async unmuteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unmute`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async pinStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/pin`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - public async unpinStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unpin`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.status(res.data) - }) - }) - } - - // ====================================== - // statuses/media - // ====================================== - public async uploadMedia( - file: any, - options?: { description?: string; focus?: string } - ): Promise> { - 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: MastodonAPI.Converter.async_attachment(res.data) - }) - }) - } - - public async getMedia(id: string): Promise> { - const res = await this.client.get(`/api/v1/media/${id}`) - - return Object.assign(res, { - data: MastodonAPI.Converter.attachment(res.data) - }) - } - - public async updateMedia( - id: string, - options?: { - file?: any - description?: string - focus?: string - } - ): Promise> { - 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: MastodonAPI.Converter.attachment(res.data) - }) - }) - } - - // ====================================== - // statuses/polls - // ====================================== - public async getPoll(id: string): Promise> { - return this.client.get(`/api/v1/polls/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.poll(res.data) - }) - }) - } - - public async votePoll(id: string, choices: Array): Promise> { - return this.client - .post(`/api/v1/polls/${id}/votes`, { - choices: choices - }) - .then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.poll(res.data) - }) - }) - } - - // ====================================== - // statuses/scheduled_statuses - // ====================================== - public async getScheduledStatuses(options?: { - limit?: number | null - max_id?: string | null - since_id?: string | null - min_id?: string | null - }): Promise>> { - 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 => MastodonAPI.Converter.scheduled_status(s)) - }) - }) - } - - public async getScheduledStatus(id: string): Promise> { - return this.client.get(`/api/v1/scheduled_statuses/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.scheduled_status(res.data) - }) - }) - } - - public async scheduleStatus(id: string, scheduled_at?: string | null): Promise> { - let params = {} - if (scheduled_at) { - params = Object.assign(params, { - scheduled_at: scheduled_at - }) - } - return this.client.put(`/api/v1/scheduled_statuses/${id}`, params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.scheduled_status(res.data) - }) - }) - } - - public cancelScheduledStatus(id: string): Promise> { - return this.client.del<{}>(`/api/v1/scheduled_statuses/${id}`) - } - - // ====================================== - // timelines - // ====================================== - public async getPublicTimeline(options?: { - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - public async getLocalTimeline(options?: { - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - public async getTagTimeline( - hashtag: string, - options?: { - local?: boolean - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - } - ): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - public async getHomeTimeline(options?: { - local?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - public async getListTimeline( - list_id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - } - ): Promise>> { - 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 => MastodonAPI.Converter.status(s)) - }) - }) - } - - // ====================================== - // timelines/conversations - // ====================================== - public async getConversationTimeline(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => MastodonAPI.Converter.conversation(c)) - }) - }) - } - - public deleteConversation(id: string): Promise> { - return this.client.del<{}>(`/api/v1/conversations/${id}`) - } - - public async readConversation(id: string): Promise> { - return this.client.post(`/api/v1/conversations/${id}/read`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.conversation(res.data) - }) - }) - } - - // ====================================== - // timelines/lists - // ====================================== - public async getLists(): Promise>> { - return this.client.get>('/api/v1/lists').then(res => { - return Object.assign(res, { - data: res.data.map(l => MastodonAPI.Converter.list(l)) - }) - }) - } - - public async getList(id: string): Promise> { - return this.client.get(`/api/v1/lists/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.list(res.data) - }) - }) - } - - public async createList(title: string): Promise> { - return this.client - .post('/api/v1/lists', { - title: title - }) - .then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.list(res.data) - }) - }) - } - - public async updateList(id: string, title: string): Promise> { - return this.client - .put(`/api/v1/lists/${id}`, { - title: title - }) - .then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.list(res.data) - }) - }) - } - - public deleteList(id: string): Promise> { - return this.client.del<{}>(`/api/v1/lists/${id}`) - } - - public async getAccountsInList( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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 => MastodonAPI.Converter.account(a)) - }) - }) - } - - public addAccountsToList(id: string, account_ids: Array): Promise> { - return this.client.post<{}>(`/api/v1/lists/${id}/accounts`, { - account_ids: account_ids - }) - } - - public deleteAccountsFromList(id: string, account_ids: Array): Promise> { - return this.client.del<{}>(`/api/v1/lists/${id}/accounts`, { - account_ids: account_ids - }) - } - - // ====================================== - // timelines/markers - // ====================================== - public async getMarkers(timeline: Array): Promise> { - return this.client.get('/api/v1/markers', { - timeline: timeline - }) - } - - public async saveMarkers(options?: { - home?: { last_read_id: string } - notifications?: { last_read_id: string } - }): Promise> { - let params = {} - if (options) { - if (options.home) { - params = Object.assign(params, { - home: options.home - }) - } - if (options.notifications) { - params = Object.assign(params, { - notifications: options.notifications - }) - } - } - return this.client.post('/api/v1/markers', params).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.marker(res.data) - }) - }) - } - - // ====================================== - // notifications - // ====================================== - public async getNotifications(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - exclude_types?: Array - account_id?: string - }): Promise>> { - 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 => MastodonAPI.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.map(n => MastodonAPI.Converter.notification(n)) - }) - }) - } - - public async getNotification(id: string): Promise> { - return this.client.get(`/api/v1/notifications/${id}`).then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.notification(res.data) - }) - }) - } - - public dismissNotifications(): Promise> { - return this.client.post<{}>('/api/v1/notifications/clear') - } - - public dismissNotification(id: string): Promise> { - return this.client.post<{}>(`/api/v1/notifications/${id}/dismiss`) - } - - public readNotifications(_options: { - id?: string - max_id?: string - }): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('mastodon does not support') - reject(err) - }) - } - - // ====================================== - // notifications/push - // ====================================== - public async subscribePushNotification( - subscription: { endpoint: string; keys: { p256dh: string; auth: string } }, - data?: { alerts: { follow?: boolean; favourite?: boolean; reblog?: boolean; mention?: boolean; poll?: boolean } } | null - ): Promise> { - 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: MastodonAPI.Converter.push_subscription(res.data) - }) - }) - } - - public async getPushSubscription(): Promise> { - return this.client.get('/api/v1/push/subscription').then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.push_subscription(res.data) - }) - }) - } - - public async updatePushSubscription( - data?: { alerts: { follow?: boolean; favourite?: boolean; reblog?: boolean; mention?: boolean; poll?: boolean } } | null - ): Promise> { - 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: MastodonAPI.Converter.push_subscription(res.data) - }) - }) - } - - public deletePushSubscription(): Promise> { - return this.client.del<{}>('/api/v1/push/subscription') - } - - // ====================================== - // search - // ====================================== - public async search( - q: string, - type: 'accounts' | 'hashtags' | 'statuses', - options?: { - limit?: number - max_id?: string - min_id?: string - resolve?: boolean - offset?: number - following?: boolean - account_id?: string - exclude_unreviewed?: boolean - } - ): Promise> { - let params = { - q, - type - } - 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.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: MastodonAPI.Converter.results(res.data) - }) - }) - } - - // ====================================== - // instance - // ====================================== - public async getInstance(): Promise> { - return this.client.get('/api/v1/instance').then(res => { - return Object.assign(res, { - data: MastodonAPI.Converter.instance(res.data) - }) - }) - } - - public getInstancePeers(): Promise>> { - return this.client.get>('/api/v1/instance/peers') - } - - public async getInstanceActivity(): Promise>> { - return this.client.get>('/api/v1/instance/activity').then(res => { - return Object.assign(res, { - data: res.data.map(a => MastodonAPI.Converter.activity(a)) - }) - }) - } - - // ====================================== - // instance/trends - // ====================================== - /** - * GET /api/v1/trends - * - * @param limit Maximum number of results to return. Defaults to 10. - */ - public async getInstanceTrends(limit?: number | null): Promise>> { - 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 => MastodonAPI.Converter.tag(t)) - }) - }) - } - - // ====================================== - // instance/directory - // ====================================== - public async getInstanceDirectory(options?: { - limit?: number - offset?: number - order?: 'active' | 'new' - local?: boolean - }): Promise>> { - 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 => MastodonAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // instance/custom_emojis - // ====================================== - public async getInstanceCustomEmojis(): Promise>> { - return this.client.get>('/api/v1/custom_emojis').then(res => { - return Object.assign(res, { - data: res.data.map(e => MastodonAPI.Converter.emoji(e)) - }) - }) - } - - // ====================================== - // instance/announcements - // ====================================== - public async getInstanceAnnouncements(with_dismissed?: boolean | null): Promise>> { - let params = {} - if (with_dismissed) { - params = Object.assign(params, { - with_dismissed - }) - } - return this.client.get>('/api/v1/announcements', params).then(res => ({ - ...res, - data: res.data.map(t => MastodonAPI.Converter.announcement(t)) - })) - } - - public async dismissInstanceAnnouncement(id: string): Promise> { - return this.client.post<{}>(`/api/v1/announcements/${id}/dismiss`) - } - - // ====================================== - // Emoji reactions - // ====================================== - public async createEmojiReaction(_id: string, _emoji: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async deleteEmojiReaction(_id: string, _emoji: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getEmojiReactions(_id: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getEmojiReaction(_id: string, _emoji: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // WebSocket - // ====================================== - public userSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'user') - } - - public publicSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'public') - } - - public localSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'public:local') - } - - public tagSocket(tag: string): WebSocket { - return this.client.socket('/api/v1/streaming', 'hashtag', `tag=${tag}`) - } - - public listSocket(list_id: string): WebSocket { - return this.client.socket('/api/v1/streaming', 'list', `list=${list_id}`) - } - - public directSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'direct') - } -} diff --git a/megalodon/src/mastodon/api_client.ts b/megalodon/src/mastodon/api_client.ts deleted file mode 100644 index 291dcaf..0000000 --- a/megalodon/src/mastodon/api_client.ts +++ /dev/null @@ -1,650 +0,0 @@ -import axios, { AxiosResponse, AxiosRequestConfig } from 'axios' -import objectAssignDeep from 'object-assign-deep' - -import WebSocket from './web_socket' -import Response from '../response' -import { RequestCanceledError } from '../cancel' -import proxyAgent, { ProxyConfig } from '../proxy_config' -import { NO_REDIRECT, DEFAULT_SCOPE, DEFAULT_UA } from '../default' -import MastodonEntity from './entity' -import MegalodonEntity from '../entity' -import NotificationType from '../notification' -import MastodonNotificationType from './notification' - -namespace MastodonAPI { - /** - * Interface - */ - export interface Interface { - get(path: string, params?: any, headers?: { [key: string]: string }, pathIsFullyQualified?: boolean): Promise> - put(path: string, params?: any, headers?: { [key: string]: string }): Promise> - putForm(path: string, params?: any, headers?: { [key: string]: string }): Promise> - patch(path: string, params?: any, headers?: { [key: string]: string }): Promise> - patchForm(path: string, params?: any, headers?: { [key: string]: string }): Promise> - post(path: string, params?: any, headers?: { [key: string]: string }): Promise> - postForm(path: string, params?: any, headers?: { [key: string]: string }): Promise> - del(path: string, params?: any, headers?: { [key: string]: string }): Promise> - cancel(): void - socket(path: string, stream: string, params?: string): WebSocket - } - - /** - * Mastodon API client. - * - * Using axios for request, you will handle promises. - */ - export class Client implements Interface { - static DEFAULT_SCOPE = DEFAULT_SCOPE - static DEFAULT_URL = 'https://mastodon.social' - static NO_REDIRECT = NO_REDIRECT - - private accessToken: string | null - private baseUrl: string - private userAgent: string - private abortController: AbortController - private proxyConfig: ProxyConfig | false = false - - /** - * @param baseUrl hostname or base URL - * @param accessToken access token from OAuth2 authorization - * @param userAgent UserAgent is specified in header on request. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor( - baseUrl: string, - accessToken: string | null = null, - userAgent: string = DEFAULT_UA, - proxyConfig: ProxyConfig | false = false - ) { - this.accessToken = accessToken - this.baseUrl = baseUrl - this.userAgent = userAgent - this.proxyConfig = proxyConfig - this.abortController = new AbortController() - axios.defaults.signal = this.abortController.signal - } - - /** - * GET request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Query parameters - * @param headers Request header object - */ - public async get( - path: string, - params = {}, - headers: { [key: string]: string } = {}, - pathIsFullyQualified = false - ): Promise> { - let options: AxiosRequestConfig = { - params: params, - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .get((pathIsFullyQualified ? '' : this.baseUrl) + path, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PUT request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async put(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .put(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PUT request to mastodon REST API for multipart. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async putForm(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .putForm(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PATCH request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async patch(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .patch(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PATCH request to mastodon REST API for multipart. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async patchForm(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .patchForm(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * POST request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data - * @param headers Request header object - */ - public async post(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios.post(this.baseUrl + path, params, options).then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * POST request to mastodon REST API for multipart. - * @param path relative path from baseUrl - * @param params Form data - * @param headers Request header object - */ - public async postForm(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios.postForm(this.baseUrl + path, params, options).then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * DELETE request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data - * @param headers Request header object - */ - public async del(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - data: params, - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .delete(this.baseUrl + path, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * Cancel all requests in this instance. - * @returns void - */ - public cancel(): void { - return this.abortController.abort() - } - - /** - * Get connection and receive websocket connection for Pleroma API. - * - * @param path relative path from baseUrl: normally it is `/streaming`. - * @param stream Stream name, please refer: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/mastodon_api/mastodon_socket.ex#L19-28 - * @returns WebSocket, which inherits from EventEmitter - */ - public socket(path: string, stream: string, params?: string): WebSocket { - if (!this.accessToken) { - throw new Error('accessToken is required') - } - const url = this.baseUrl + path - const streaming = new WebSocket(url, stream, params, this.accessToken, this.userAgent, this.proxyConfig) - process.nextTick(() => { - streaming.start() - }) - return streaming - } - } - - export namespace Entity { - export type Account = MastodonEntity.Account - export type Activity = MastodonEntity.Activity - export type Announcement = MastodonEntity.Announcement - export type Application = MastodonEntity.Application - export type AsyncAttachment = MegalodonEntity.AsyncAttachment - export type Attachment = MastodonEntity.Attachment - export type Card = MastodonEntity.Card - export type Context = MastodonEntity.Context - export type Conversation = MastodonEntity.Conversation - export type Emoji = MastodonEntity.Emoji - export type FeaturedTag = MastodonEntity.FeaturedTag - export type Field = MastodonEntity.Field - export type Filter = MastodonEntity.Filter - export type History = MastodonEntity.History - export type IdentityProof = MastodonEntity.IdentityProof - export type Instance = MastodonEntity.Instance - export type List = MastodonEntity.List - export type Marker = MastodonEntity.Marker - export type Mention = MastodonEntity.Mention - export type Notification = MastodonEntity.Notification - export type Poll = MastodonEntity.Poll - export type PollOption = MastodonEntity.PollOption - export type Preferences = MastodonEntity.Preferences - export type PushSubscription = MastodonEntity.PushSubscription - export type Relationship = MastodonEntity.Relationship - export type Reaction = MastodonEntity.Reaction - export type Report = MastodonEntity.Report - export type Results = MastodonEntity.Results - export type ScheduledStatus = MastodonEntity.ScheduledStatus - export type Source = MastodonEntity.Source - export type Stats = MastodonEntity.Stats - export type Status = MastodonEntity.Status - export type StatusParams = MastodonEntity.StatusParams - export type Tag = MastodonEntity.Tag - export type Token = MastodonEntity.Token - export type URLs = MastodonEntity.URLs - } - - export namespace Converter { - export const encodeNotificationType = (t: MegalodonEntity.NotificationType): MastodonEntity.NotificationType => { - switch (t) { - case NotificationType.Follow: - return MastodonNotificationType.Follow - case NotificationType.Favourite: - return MastodonNotificationType.Favourite - case NotificationType.Reblog: - return MastodonNotificationType.Reblog - case NotificationType.Mention: - return MastodonNotificationType.Mention - case NotificationType.FollowRequest: - return MastodonNotificationType.FollowRequest - case NotificationType.Status: - return MastodonNotificationType.Status - case NotificationType.PollExpired: - return MastodonNotificationType.Poll - default: - return t - } - } - - export const decodeNotificationType = (t: MastodonEntity.NotificationType): MegalodonEntity.NotificationType => { - switch (t) { - case MastodonNotificationType.Follow: - return NotificationType.Follow - case MastodonNotificationType.Favourite: - return NotificationType.Favourite - case MastodonNotificationType.Mention: - return NotificationType.Mention - case MastodonNotificationType.Reblog: - return NotificationType.Reblog - case MastodonNotificationType.FollowRequest: - return NotificationType.FollowRequest - case MastodonNotificationType.Status: - return NotificationType.Status - case MastodonNotificationType.Poll: - return NotificationType.PollExpired - default: - return t - } - } - - export const account = (a: Entity.Account): MegalodonEntity.Account => a - export const activity = (a: Entity.Activity): MegalodonEntity.Activity => a - export const announcement = (a: Entity.Announcement): MegalodonEntity.Announcement => ({ - ...a, - reactions: a.reactions.map(r => reaction(r)) - }) - export const application = (a: Entity.Application): MegalodonEntity.Application => a - export const attachment = (a: Entity.Attachment): MegalodonEntity.Attachment => a - export const async_attachment = (a: Entity.AsyncAttachment) => { - if (a.url) { - return { - id: a.id, - type: a.type, - url: a.url!, - remote_url: a.remote_url, - preview_url: a.preview_url, - text_url: a.text_url, - meta: a.meta, - description: a.description, - blurhash: a.blurhash - } as MegalodonEntity.Attachment - } else { - return a as MegalodonEntity.AsyncAttachment - } - } - export const card = (c: Entity.Card): MegalodonEntity.Card => c - export const context = (c: Entity.Context): MegalodonEntity.Context => ({ - ancestors: c.ancestors.map(a => status(a)), - descendants: c.descendants.map(d => status(d)) - }) - export const conversation = (c: Entity.Conversation): MegalodonEntity.Conversation => ({ - id: c.id, - accounts: c.accounts.map(a => account(a)), - last_status: c.last_status ? status(c.last_status) : null, - unread: c.unread - }) - export const emoji = (e: Entity.Emoji): MegalodonEntity.Emoji => e - export const featured_tag = (e: Entity.FeaturedTag): MegalodonEntity.FeaturedTag => e - export const field = (f: Entity.Field): MegalodonEntity.Field => f - export const filter = (f: Entity.Filter): MegalodonEntity.Filter => f - export const history = (h: Entity.History): MegalodonEntity.History => h - export const identity_proof = (i: Entity.IdentityProof): MegalodonEntity.IdentityProof => i - export const instance = (i: Entity.Instance): MegalodonEntity.Instance => i - export const list = (l: Entity.List): MegalodonEntity.List => l - export const marker = (m: Entity.Marker): MegalodonEntity.Marker => m - export const mention = (m: Entity.Mention): MegalodonEntity.Mention => m - export const notification = (n: Entity.Notification): MegalodonEntity.Notification => { - if (n.status) { - return { - account: account(n.account), - created_at: n.created_at, - id: n.id, - status: status(n.status), - type: decodeNotificationType(n.type) - } - } else { - return { - account: account(n.account), - created_at: n.created_at, - id: n.id, - type: decodeNotificationType(n.type) - } - } - } - export const poll = (p: Entity.Poll): MegalodonEntity.Poll => p - export const poll_option = (p: Entity.PollOption): MegalodonEntity.PollOption => p - export const preferences = (p: Entity.Preferences): MegalodonEntity.Preferences => p - export const push_subscription = (p: Entity.PushSubscription): MegalodonEntity.PushSubscription => p - export const relationship = (r: Entity.Relationship): MegalodonEntity.Relationship => r - export const reaction = (r: Entity.Reaction): MegalodonEntity.Reaction => ({ - count: r.count, - me: r.me ?? false, - name: r.name, - url: r.url, - }) - export const report = (r: Entity.Report): MegalodonEntity.Report => r - export const results = (r: Entity.Results): MegalodonEntity.Results => ({ - accounts: r.accounts.map(a => account(a)), - statuses: r.statuses.map(s => status(s)), - hashtags: r.hashtags.map(h => tag(h)) - }) - export const scheduled_status = (s: Entity.ScheduledStatus): MegalodonEntity.ScheduledStatus => s - export const source = (s: Entity.Source): MegalodonEntity.Source => s - export const stats = (s: Entity.Stats): MegalodonEntity.Stats => s - export const status = (s: Entity.Status): MegalodonEntity.Status => ({ - id: s.id, - uri: s.uri, - url: s.url, - account: account(s.account), - in_reply_to_id: s.in_reply_to_id, - in_reply_to_account_id: s.in_reply_to_account_id, - reblog: s.reblog ? status(s.reblog) : s.quote ? status(s.quote) : null, - content: s.content, - plain_content: null, - created_at: s.created_at, - emojis: s.emojis.map(e => emoji(e)), - replies_count: s.replies_count, - reblogs_count: s.reblogs_count, - favourites_count: s.favourites_count, - reblogged: s.reblogged, - favourited: s.favourited, - muted: s.muted, - sensitive: s.sensitive, - spoiler_text: s.spoiler_text, - visibility: s.visibility, - media_attachments: s.media_attachments.map(m => attachment(m)), - mentions: s.mentions.map(m => mention(m)), - tags: s.tags.map(t => tag(t)), - card: s.card ? card(s.card) : null, - poll: s.poll ? poll(s.poll) : null, - application: s.application ? application(s.application) : null, - language: s.language, - pinned: s.pinned, - emoji_reactions: [], - bookmarked: s.bookmarked ? s.bookmarked : false, - // Now quote is supported only fedibird.com. - quote: s.quote ? status(s.quote) : null - }) - export const status_params = (s: Entity.StatusParams): MegalodonEntity.StatusParams => s - export const tag = (t: Entity.Tag): MegalodonEntity.Tag => t - export const token = (t: Entity.Token): MegalodonEntity.Token => t - export const urls = (u: Entity.URLs): MegalodonEntity.URLs => u - } -} -export default MastodonAPI diff --git a/megalodon/src/mastodon/entities/account.ts b/megalodon/src/mastodon/entities/account.ts deleted file mode 100644 index e83b18e..0000000 --- a/megalodon/src/mastodon/entities/account.ts +++ /dev/null @@ -1,27 +0,0 @@ -/// -/// -/// -namespace MastodonEntity { - export type Account = { - id: string - username: string - acct: string - display_name: string - locked: boolean - created_at: string - followers_count: number - following_count: number - statuses_count: number - note: string - url: string - avatar: string - avatar_static: string - header: string - header_static: string - emojis: Array - moved: Account | null - fields: Array - bot: boolean | null - source?: Source - } -} diff --git a/megalodon/src/mastodon/entities/activity.ts b/megalodon/src/mastodon/entities/activity.ts deleted file mode 100644 index 3e84c9d..0000000 --- a/megalodon/src/mastodon/entities/activity.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace MastodonEntity { - export type Activity = { - week: string - statuses: string - logins: string - registrations: string - } -} diff --git a/megalodon/src/mastodon/entities/announcement.ts b/megalodon/src/mastodon/entities/announcement.ts deleted file mode 100644 index d55b635..0000000 --- a/megalodon/src/mastodon/entities/announcement.ts +++ /dev/null @@ -1,41 +0,0 @@ -/// -/// - -namespace MastodonEntity { - export type Announcement = { - id: string - content: string - starts_at: string | null - ends_at: string | null - published: boolean - all_day: boolean - published_at: string - updated_at: string - read?: boolean - mentions: Array - statuses: Array - tags: Array - emojis: Array - reactions: Array - } - - export type AnnouncementAccount = { - id: string - username: string - url: string - acct: string - } - - export type AnnouncementStatus = { - id: string - url: string - } - - export type Reaction = { - name: string - count: number - me?: boolean - url?: string - static_url?: string - } -} diff --git a/megalodon/src/mastodon/entities/application.ts b/megalodon/src/mastodon/entities/application.ts deleted file mode 100644 index a3f0799..0000000 --- a/megalodon/src/mastodon/entities/application.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace MastodonEntity { - export type Application = { - name: string - website?: string | null - vapid_key?: string | null - } -} diff --git a/megalodon/src/mastodon/entities/async_attachment.ts b/megalodon/src/mastodon/entities/async_attachment.ts deleted file mode 100644 index 45f574d..0000000 --- a/megalodon/src/mastodon/entities/async_attachment.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// -namespace MastodonEntity { - export type AsyncAttachment = { - id: string - type: 'unknown' | 'image' | 'gifv' | 'video' | 'audio' - url: string | null - remote_url: string | null - preview_url: string - text_url: string | null - meta: Meta | null - description: string | null - blurhash: string | null - } -} diff --git a/megalodon/src/mastodon/entities/attachment.ts b/megalodon/src/mastodon/entities/attachment.ts deleted file mode 100644 index ec51c5b..0000000 --- a/megalodon/src/mastodon/entities/attachment.ts +++ /dev/null @@ -1,49 +0,0 @@ -namespace MastodonEntity { - export type Sub = { - // For Image, Gifv, and Video - width?: number - height?: number - size?: string - aspect?: number - - // For Gifv and Video - frame_rate?: string - - // For Audio, Gifv, and Video - duration?: number - bitrate?: number - } - - export type Focus = { - x: number - y: number - } - - export type Meta = { - original?: Sub - small?: Sub - focus?: Focus - length?: string - duration?: number - fps?: number - size?: string - width?: number - height?: number - aspect?: number - audio_encode?: string - audio_bitrate?: string - audio_channel?: string - } - - export type Attachment = { - id: string - type: 'unknown' | 'image' | 'gifv' | 'video' | 'audio' - url: string - remote_url: string | null - preview_url: string | null - text_url: string | null - meta: Meta | null - description: string | null - blurhash: string | null - } -} diff --git a/megalodon/src/mastodon/entities/card.ts b/megalodon/src/mastodon/entities/card.ts deleted file mode 100644 index e8ec0ec..0000000 --- a/megalodon/src/mastodon/entities/card.ts +++ /dev/null @@ -1,16 +0,0 @@ -namespace MastodonEntity { - export type Card = { - url: string - title: string - description: string - type: 'link' | 'photo' | 'video' | 'rich' - image?: string - author_name?: string - author_url?: string - provider_name?: string - provider_url?: string - html?: string - width?: number - height?: number - } -} diff --git a/megalodon/src/mastodon/entities/context.ts b/megalodon/src/mastodon/entities/context.ts deleted file mode 100644 index c2b6e26..0000000 --- a/megalodon/src/mastodon/entities/context.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -namespace MastodonEntity { - export type Context = { - ancestors: Array - descendants: Array - } -} diff --git a/megalodon/src/mastodon/entities/conversation.ts b/megalodon/src/mastodon/entities/conversation.ts deleted file mode 100644 index 0ee3f1d..0000000 --- a/megalodon/src/mastodon/entities/conversation.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// -/// - -namespace MastodonEntity { - export type Conversation = { - id: string - accounts: Array - last_status: Status | null - unread: boolean - } -} diff --git a/megalodon/src/mastodon/entities/emoji.ts b/megalodon/src/mastodon/entities/emoji.ts deleted file mode 100644 index 530c52d..0000000 --- a/megalodon/src/mastodon/entities/emoji.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace MastodonEntity { - export type Emoji = { - shortcode: string - static_url: string - url: string - visible_in_picker: boolean - category: string - } -} diff --git a/megalodon/src/mastodon/entities/featured_tag.ts b/megalodon/src/mastodon/entities/featured_tag.ts deleted file mode 100644 index a2628b9..0000000 --- a/megalodon/src/mastodon/entities/featured_tag.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace MastodonEntity { - export type FeaturedTag = { - id: string - name: string - statuses_count: number - last_status_at: string - } -} diff --git a/megalodon/src/mastodon/entities/field.ts b/megalodon/src/mastodon/entities/field.ts deleted file mode 100644 index b6ada5d..0000000 --- a/megalodon/src/mastodon/entities/field.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace MastodonEntity { - export type Field = { - name: string - value: string - verified_at: string | null - } -} diff --git a/megalodon/src/mastodon/entities/filter.ts b/megalodon/src/mastodon/entities/filter.ts deleted file mode 100644 index 1e17e61..0000000 --- a/megalodon/src/mastodon/entities/filter.ts +++ /dev/null @@ -1,12 +0,0 @@ -namespace MastodonEntity { - export type Filter = { - id: string - phrase: string - context: Array - expires_at: string | null - irreversible: boolean - whole_word: boolean - } - - export type FilterContext = string -} diff --git a/megalodon/src/mastodon/entities/history.ts b/megalodon/src/mastodon/entities/history.ts deleted file mode 100644 index cc1a3b4..0000000 --- a/megalodon/src/mastodon/entities/history.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace MastodonEntity { - export type History = { - day: string - uses: number - accounts: number - } -} diff --git a/megalodon/src/mastodon/entities/identity_proof.ts b/megalodon/src/mastodon/entities/identity_proof.ts deleted file mode 100644 index a4dab9e..0000000 --- a/megalodon/src/mastodon/entities/identity_proof.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace MastodonEntity { - export type IdentityProof = { - provider: string - provider_username: string - updated_at: string - proof_url: string - profile_url: string - } -} diff --git a/megalodon/src/mastodon/entities/instance.ts b/megalodon/src/mastodon/entities/instance.ts deleted file mode 100644 index b37a665..0000000 --- a/megalodon/src/mastodon/entities/instance.ts +++ /dev/null @@ -1,41 +0,0 @@ -/// -/// -/// - -namespace MastodonEntity { - export type Instance = { - uri: string - title: string - description: string - email: string - version: string - thumbnail: string | null - urls: URLs - stats: Stats - languages: Array - contact_account: Account | null - max_toot_chars?: number - registrations?: boolean - configuration?: { - statuses: { - max_characters: number - max_media_attachments: number - characters_reserved_per_url: number - } - media_attachments: { - supported_mime_types: Array - image_size_limit: number - image_matrix_limit: number - video_size_limit: number - video_frame_limit: number - video_matrix_limit: number - } - polls: { - max_options: number - max_characters_per_option: number - min_expiration: number - max_expiration: number - } - } - } -} diff --git a/megalodon/src/mastodon/entities/list.ts b/megalodon/src/mastodon/entities/list.ts deleted file mode 100644 index f368571..0000000 --- a/megalodon/src/mastodon/entities/list.ts +++ /dev/null @@ -1,6 +0,0 @@ -namespace MastodonEntity { - export type List = { - id: string - title: string - } -} diff --git a/megalodon/src/mastodon/entities/marker.ts b/megalodon/src/mastodon/entities/marker.ts deleted file mode 100644 index 1b0983e..0000000 --- a/megalodon/src/mastodon/entities/marker.ts +++ /dev/null @@ -1,14 +0,0 @@ -namespace MastodonEntity { - export type Marker = { - home: { - last_read_id: string - version: number - updated_at: string - } - notifications: { - last_read_id: string - version: number - updated_at: string - } - } -} diff --git a/megalodon/src/mastodon/entities/mention.ts b/megalodon/src/mastodon/entities/mention.ts deleted file mode 100644 index ddc99d9..0000000 --- a/megalodon/src/mastodon/entities/mention.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace MastodonEntity { - export type Mention = { - id: string - username: string - url: string - acct: string - } -} diff --git a/megalodon/src/mastodon/entities/notification.ts b/megalodon/src/mastodon/entities/notification.ts deleted file mode 100644 index ad5519b..0000000 --- a/megalodon/src/mastodon/entities/notification.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// -/// - -namespace MastodonEntity { - export type Notification = { - account: Account - created_at: string - id: string - status?: Status - type: NotificationType - } - - export type NotificationType = string -} diff --git a/megalodon/src/mastodon/entities/poll.ts b/megalodon/src/mastodon/entities/poll.ts deleted file mode 100644 index eaf0905..0000000 --- a/megalodon/src/mastodon/entities/poll.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -namespace MastodonEntity { - export type Poll = { - id: string - expires_at: string | null - expired: boolean - multiple: boolean - votes_count: number - options: Array - voted: boolean - } -} diff --git a/megalodon/src/mastodon/entities/poll_option.ts b/megalodon/src/mastodon/entities/poll_option.ts deleted file mode 100644 index d3c1419..0000000 --- a/megalodon/src/mastodon/entities/poll_option.ts +++ /dev/null @@ -1,6 +0,0 @@ -namespace MastodonEntity { - export type PollOption = { - title: string - votes_count: number | null - } -} diff --git a/megalodon/src/mastodon/entities/preferences.ts b/megalodon/src/mastodon/entities/preferences.ts deleted file mode 100644 index 3c8cc95..0000000 --- a/megalodon/src/mastodon/entities/preferences.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace MastodonEntity { - export type Preferences = { - 'posting:default:visibility': 'public' | 'unlisted' | 'private' | 'direct' - 'posting:default:sensitive': boolean - 'posting:default:language': string | null - 'reading:expand:media': 'default' | 'show_all' | 'hide_all' - 'reading:expand:spoilers': boolean - } -} diff --git a/megalodon/src/mastodon/entities/push_subscription.ts b/megalodon/src/mastodon/entities/push_subscription.ts deleted file mode 100644 index ad96ea6..0000000 --- a/megalodon/src/mastodon/entities/push_subscription.ts +++ /dev/null @@ -1,16 +0,0 @@ -namespace MastodonEntity { - export type Alerts = { - follow: boolean - favourite: boolean - mention: boolean - reblog: boolean - poll: boolean - } - - export type PushSubscription = { - id: string - endpoint: string - server_key: string - alerts: Alerts - } -} diff --git a/megalodon/src/mastodon/entities/relationship.ts b/megalodon/src/mastodon/entities/relationship.ts deleted file mode 100644 index 830ac51..0000000 --- a/megalodon/src/mastodon/entities/relationship.ts +++ /dev/null @@ -1,18 +0,0 @@ -namespace MastodonEntity { - export type Relationship = { - id: string - following: boolean - followed_by: boolean - delivery_following: boolean - blocking: boolean - blocked_by: boolean - muting: boolean - muting_notifications: boolean - requested: boolean - domain_blocking: boolean - showing_reblogs: boolean - endorsed: boolean - notifying: boolean - note: string - } -} diff --git a/megalodon/src/mastodon/entities/report.ts b/megalodon/src/mastodon/entities/report.ts deleted file mode 100644 index 79ab478..0000000 --- a/megalodon/src/mastodon/entities/report.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace MastodonEntity { - export type Report = { - id: string - action_taken: string - comment: string - account_id: string - status_ids: Array - } -} diff --git a/megalodon/src/mastodon/entities/results.ts b/megalodon/src/mastodon/entities/results.ts deleted file mode 100644 index a1c9065..0000000 --- a/megalodon/src/mastodon/entities/results.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// -/// -/// - -namespace MastodonEntity { - export type Results = { - accounts: Array - statuses: Array - hashtags: Array - } -} diff --git a/megalodon/src/mastodon/entities/scheduled_status.ts b/megalodon/src/mastodon/entities/scheduled_status.ts deleted file mode 100644 index 2388311..0000000 --- a/megalodon/src/mastodon/entities/scheduled_status.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// -/// -namespace MastodonEntity { - export type ScheduledStatus = { - id: string - scheduled_at: string - params: StatusParams - media_attachments: Array - } -} diff --git a/megalodon/src/mastodon/entities/source.ts b/megalodon/src/mastodon/entities/source.ts deleted file mode 100644 index c104602..0000000 --- a/megalodon/src/mastodon/entities/source.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// -namespace MastodonEntity { - export type Source = { - privacy: string | null - sensitive: boolean | null - language: string | null - note: string - fields: Array - } -} diff --git a/megalodon/src/mastodon/entities/stats.ts b/megalodon/src/mastodon/entities/stats.ts deleted file mode 100644 index 925da85..0000000 --- a/megalodon/src/mastodon/entities/stats.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace MastodonEntity { - export type Stats = { - user_count: number - status_count: number - domain_count: number - } -} diff --git a/megalodon/src/mastodon/entities/status.ts b/megalodon/src/mastodon/entities/status.ts deleted file mode 100644 index 449b418..0000000 --- a/megalodon/src/mastodon/entities/status.ts +++ /dev/null @@ -1,44 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -/// - -namespace MastodonEntity { - export type Status = { - id: string - uri: string - url: string - account: Account - in_reply_to_id: string | null - in_reply_to_account_id: string | null - reblog: Status | null - content: string - created_at: string - emojis: Emoji[] - replies_count: number - reblogs_count: number - favourites_count: number - reblogged: boolean | null - favourited: boolean | null - muted: boolean | null - sensitive: boolean - spoiler_text: string - visibility: 'public' | 'unlisted' | 'private' | 'direct' - media_attachments: Array - mentions: Array - tags: Array - card: Card | null - poll: Poll | null - application: Application | null - language: string | null - pinned: boolean | null - bookmarked?: boolean - // These parameters are unique parameters in fedibird.com for quote. - quote_id?: string - quote?: Status | null - } -} diff --git a/megalodon/src/mastodon/entities/status_params.ts b/megalodon/src/mastodon/entities/status_params.ts deleted file mode 100644 index 3312960..0000000 --- a/megalodon/src/mastodon/entities/status_params.ts +++ /dev/null @@ -1,12 +0,0 @@ -namespace MastodonEntity { - export type StatusParams = { - text: string - in_reply_to_id: string | null - media_ids: Array | null - sensitive: boolean | null - spoiler_text: string | null - visibility: 'public' | 'unlisted' | 'private' | 'direct' - scheduled_at: string | null - application_id: string - } -} diff --git a/megalodon/src/mastodon/entities/tag.ts b/megalodon/src/mastodon/entities/tag.ts deleted file mode 100644 index d50cb66..0000000 --- a/megalodon/src/mastodon/entities/tag.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -namespace MastodonEntity { - export type Tag = { - name: string - url: string - history: Array | null - following?: boolean - } -} diff --git a/megalodon/src/mastodon/entities/token.ts b/megalodon/src/mastodon/entities/token.ts deleted file mode 100644 index 128663e..0000000 --- a/megalodon/src/mastodon/entities/token.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace MastodonEntity { - export type Token = { - access_token: string - token_type: string - scope: string - created_at: number - } -} diff --git a/megalodon/src/mastodon/entities/urls.ts b/megalodon/src/mastodon/entities/urls.ts deleted file mode 100644 index 4f6b55a..0000000 --- a/megalodon/src/mastodon/entities/urls.ts +++ /dev/null @@ -1,5 +0,0 @@ -namespace MastodonEntity { - export type URLs = { - streaming_api: string - } -} diff --git a/megalodon/src/mastodon/entity.ts b/megalodon/src/mastodon/entity.ts deleted file mode 100644 index dc96c6e..0000000 --- a/megalodon/src/mastodon/entity.ts +++ /dev/null @@ -1,37 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// - -export default MastodonEntity diff --git a/megalodon/src/mastodon/notification.ts b/megalodon/src/mastodon/notification.ts deleted file mode 100644 index a426c55..0000000 --- a/megalodon/src/mastodon/notification.ts +++ /dev/null @@ -1,13 +0,0 @@ -import MastodonEntity from './entity' - -namespace MastodonNotificationType { - export const Mention: MastodonEntity.NotificationType = 'mention' - export const Reblog: MastodonEntity.NotificationType = 'reblog' - export const Favourite: MastodonEntity.NotificationType = 'favourite' - export const Follow: MastodonEntity.NotificationType = 'follow' - export const Poll: MastodonEntity.NotificationType = 'poll' - export const FollowRequest: MastodonEntity.NotificationType = 'follow_request' - export const Status: MastodonEntity.NotificationType = 'status' -} - -export default MastodonNotificationType diff --git a/megalodon/src/mastodon/web_socket.ts b/megalodon/src/mastodon/web_socket.ts deleted file mode 100644 index f4806de..0000000 --- a/megalodon/src/mastodon/web_socket.ts +++ /dev/null @@ -1,342 +0,0 @@ -import WS from 'ws' -import dayjs, { Dayjs } from 'dayjs' -import { EventEmitter } from 'events' -import proxyAgent, { ProxyConfig } from '../proxy_config' -import { WebSocketInterface } from '../megalodon' -import MastodonAPI from './api_client' - -/** - * WebSocket - * Pleroma is not support streaming. It is support websocket instead of streaming. - * So this class connect to Phoenix websocket for Pleroma. - */ -export default class WebSocket extends EventEmitter implements WebSocketInterface { - public url: string - public stream: string - public params: string | null - public parser: Parser - public headers: { [key: string]: string } - public proxyConfig: ProxyConfig | false = false - private _accessToken: string - private _reconnectInterval: number - private _reconnectMaxAttempts: number - private _reconnectCurrentAttempts: number - private _connectionClosed: boolean - private _client: WS | null - private _pongReceivedTimestamp: Dayjs - private _heartbeatInterval: number = 60000 - private _pongWaiting: boolean = false - - /** - * @param url Full url of websocket: e.g. https://pleroma.io/api/v1/streaming - * @param stream Stream name, please refer: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/mastodon_api/mastodon_socket.ex#L19-28 - * @param accessToken The access token. - * @param userAgent The specified User Agent. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor( - url: string, - stream: string, - params: string | undefined, - accessToken: string, - userAgent: string, - proxyConfig: ProxyConfig | false = false - ) { - super() - this.url = url - this.stream = stream - if (params === undefined) { - this.params = null - } else { - this.params = params - } - this.parser = new Parser() - this.headers = { - 'User-Agent': userAgent - } - this.proxyConfig = proxyConfig - this._accessToken = accessToken - this._reconnectInterval = 10000 - this._reconnectMaxAttempts = Infinity - this._reconnectCurrentAttempts = 0 - this._connectionClosed = false - this._client = null - this._pongReceivedTimestamp = dayjs() - } - - /** - * Start websocket connection. - */ - public start() { - this._connectionClosed = false - this._resetRetryParams() - this._startWebSocketConnection() - } - - /** - * Reset connection and start new websocket connection. - */ - private _startWebSocketConnection() { - this._resetConnection() - this._setupParser() - this._client = this._connect(this.url, this.stream, this.params, this._accessToken, this.headers, this.proxyConfig) - this._bindSocket(this._client) - } - - /** - * Stop current connection. - */ - public stop() { - this._connectionClosed = true - this._resetConnection() - this._resetRetryParams() - } - - /** - * Clean up current connection, and listeners. - */ - private _resetConnection() { - if (this._client) { - this._client.close(1000) - this._client.removeAllListeners() - this._client = null - } - - if (this.parser) { - this.parser.removeAllListeners() - } - } - - /** - * Resets the parameters used in reconnect. - */ - private _resetRetryParams() { - this._reconnectCurrentAttempts = 0 - } - - /** - * Reconnects to the same endpoint. - */ - private _reconnect() { - setTimeout(() => { - // Skip reconnect when client is connecting. - // https://github.com/websockets/ws/blob/7.2.1/lib/websocket.js#L365 - if (this._client && this._client.readyState === WS.CONNECTING) { - return - } - - if (this._reconnectCurrentAttempts < this._reconnectMaxAttempts) { - this._reconnectCurrentAttempts++ - this._clearBinding() - if (this._client) { - // In reconnect, we want to close the connection immediately, - // because recoonect is necessary when some problems occur. - this._client.terminate() - } - // Call connect methods - console.log('Reconnecting') - this._client = this._connect(this.url, this.stream, this.params, this._accessToken, this.headers, this.proxyConfig) - this._bindSocket(this._client) - } - }, this._reconnectInterval) - } - - /** - * @param url Base url of streaming endpoint. - * @param stream The specified stream name. - * @param accessToken Access token. - * @param headers The specified headers. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - * @return A WebSocket instance. - */ - private _connect( - url: string, - stream: string, - params: string | null, - accessToken: string, - headers: { [key: string]: string }, - proxyConfig: ProxyConfig | false - ): WS { - const parameter: Array = [`stream=${stream}`] - - if (params) { - parameter.push(params) - } - - if (accessToken !== null) { - parameter.push(`access_token=${accessToken}`) - } - const requestURL: string = `${url}/?${parameter.join('&')}` - let options: WS.ClientOptions = { - headers: headers - } - if (proxyConfig) { - options = Object.assign(options, { - agent: proxyAgent(proxyConfig) - }) - } - - const cli: WS = new WS(requestURL, options) - return cli - } - - /** - * Clear binding event for web socket client. - */ - private _clearBinding() { - if (this._client) { - this._client.removeAllListeners('close') - this._client.removeAllListeners('pong') - this._client.removeAllListeners('open') - this._client.removeAllListeners('message') - this._client.removeAllListeners('error') - } - } - - /** - * Bind event for web socket client. - * @param client A WebSocket instance. - */ - private _bindSocket(client: WS) { - client.on('close', (code: number, _reason: Buffer) => { - // Refer the code: https://tools.ietf.org/html/rfc6455#section-7.4 - if (code === 1000) { - this.emit('close', {}) - } else { - console.log(`Closed connection with ${code}`) - // If already called close method, it does not retry. - if (!this._connectionClosed) { - this._reconnect() - } - } - }) - client.on('pong', () => { - this._pongWaiting = false - this.emit('pong', {}) - this._pongReceivedTimestamp = dayjs() - // It is required to anonymous function since get this scope in checkAlive. - setTimeout(() => this._checkAlive(this._pongReceivedTimestamp), this._heartbeatInterval) - }) - client.on('open', () => { - this.emit('connect', {}) - // Call first ping event. - setTimeout(() => { - client.ping('') - }, 10000) - }) - client.on('message', (data: WS.Data, isBinary: boolean) => { - this.parser.parse(data, isBinary) - }) - client.on('error', (err: Error) => { - this.emit('error', err) - }) - } - - /** - * Set up parser when receive message. - */ - private _setupParser() { - this.parser.on('update', (status: MastodonAPI.Entity.Status) => { - this.emit('update', MastodonAPI.Converter.status(status)) - }) - this.parser.on('notification', (notification: MastodonAPI.Entity.Notification) => { - this.emit('notification', MastodonAPI.Converter.notification(notification)) - }) - this.parser.on('delete', (id: string) => { - this.emit('delete', id) - }) - this.parser.on('conversation', (conversation: MastodonAPI.Entity.Conversation) => { - this.emit('conversation', MastodonAPI.Converter.conversation(conversation)) - }) - this.parser.on('status_update', (status: MastodonAPI.Entity.Status) => { - this.emit('status_update', MastodonAPI.Converter.status(status)) - }) - this.parser.on('error', (err: Error) => { - this.emit('parser-error', err) - }) - this.parser.on('heartbeat', _ => { - this.emit('heartbeat', 'heartbeat') - }) - } - - /** - * Call ping and wait to pong. - */ - private _checkAlive(timestamp: Dayjs) { - const now: Dayjs = dayjs() - // Block multiple calling, if multiple pong event occur. - // It the duration is less than interval, through ping. - if (now.diff(timestamp) > this._heartbeatInterval - 1000 && !this._connectionClosed) { - // Skip ping when client is connecting. - // https://github.com/websockets/ws/blob/7.2.1/lib/websocket.js#L289 - if (this._client && this._client.readyState !== WS.CONNECTING) { - this._pongWaiting = true - this._client.ping('') - setTimeout(() => { - if (this._pongWaiting) { - this._pongWaiting = false - this._reconnect() - } - }, 10000) - } - } - } -} - -/** - * Parser - * This class provides parser for websocket message. - */ -export class Parser extends EventEmitter { - /** - * @param message Message body of websocket. - */ - public parse(data: WS.Data, isBinary: boolean) { - const message = isBinary ? data : data.toString() - if (typeof message !== 'string') { - this.emit('heartbeat', {}) - return - } - - if (message === '') { - this.emit('heartbeat', {}) - return - } - - let event = '' - let payload = '' - let mes = {} - try { - const obj = JSON.parse(message) - event = obj.event - payload = obj.payload - mes = JSON.parse(payload) - } catch (err) { - // delete event does not have json object - if (event !== 'delete') { - this.emit('error', new Error(`Error parsing websocket reply: ${message}, error message: ${err}`)) - return - } - } - - switch (event) { - case 'update': - this.emit('update', mes as MastodonAPI.Entity.Status) - break - case 'notification': - this.emit('notification', mes as MastodonAPI.Entity.Notification) - break - case 'conversation': - this.emit('conversation', mes as MastodonAPI.Entity.Conversation) - break - case 'delete': - this.emit('delete', payload) - break - case 'status.update': - this.emit('status_update', mes as MastodonAPI.Entity.Status) - break - default: - this.emit('error', new Error(`Unknown event has received: ${message}`)) - } - } -} diff --git a/megalodon/src/megalodon.ts b/megalodon/src/megalodon.ts index 29d589a..47b7d28 100644 --- a/megalodon/src/megalodon.ts +++ b/megalodon/src/megalodon.ts @@ -1,8 +1,6 @@ import Response from './response' import OAuth from './oauth' -import Pleroma from './pleroma' import proxyAgent, { ProxyConfig } from './proxy_config' -import Mastodon from './mastodon' import Entity from './entity' import axios, { AxiosRequestConfig } from 'axios' import Misskey from './misskey' @@ -1373,7 +1371,6 @@ export const detector = async (url: string, proxyConfig: ProxyConfig | false = f /** * Get client for each SNS according to megalodon interface. * - * @param sns Name of your SNS, `mastodon` or `pleroma`. * @param baseUrl hostname or base URL. * @param accessToken access token from OAuth2 authorization * @param userAgent UserAgent is specified in header on request. @@ -1381,26 +1378,10 @@ export const detector = async (url: string, proxyConfig: ProxyConfig | false = f * @return Client instance for each SNS you specified. */ const generator = ( - sns: 'mastodon' | 'pleroma' | 'misskey', baseUrl: string, accessToken: string | null = null, userAgent: string | null = null, proxyConfig: ProxyConfig | false = false -): MegalodonInterface => { - switch (sns) { - case 'pleroma': { - const pleroma = new Pleroma(baseUrl, accessToken, userAgent, proxyConfig) - return pleroma - } - case 'misskey': { - const misskey = new Misskey(baseUrl, accessToken, userAgent, proxyConfig) - return misskey - } - default: { - const mastodon = new Mastodon(baseUrl, accessToken, userAgent, proxyConfig) - return mastodon - } - } -} +): MegalodonInterface => new Misskey(baseUrl, accessToken, userAgent, proxyConfig) export default generator diff --git a/megalodon/src/pleroma.ts b/megalodon/src/pleroma.ts deleted file mode 100644 index c306b95..0000000 --- a/megalodon/src/pleroma.ts +++ /dev/null @@ -1,2344 +0,0 @@ -import { OAuth2 } from 'oauth' -import FormData from 'form-data' - -import PleromaAPI from './pleroma/api_client' -import WebSocket from './pleroma/web_socket' -import { MegalodonInterface, ArgumentError } from './megalodon' -import Response from './response' -import Entity from './entity' -import { NO_REDIRECT, DEFAULT_SCOPE, DEFAULT_UA } from './default' -import { ProxyConfig } from './proxy_config' -import OAuth from './oauth' - -export default class Pleroma implements MegalodonInterface { - public client: PleromaAPI.Interface - public baseUrl: string - - /** - * @param baseUrl hostname or base URL - * @param accessToken access token from OAuth2 authorization - * @param userAgent UserAgent is specified in header on request. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor( - baseUrl: string, - accessToken: string | null = null, - userAgent: string | null = DEFAULT_UA, - proxyConfig: ProxyConfig | false = false - ) { - let token: string = '' - if (accessToken) { - token = accessToken - } - let agent: string = DEFAULT_UA - if (userAgent) { - agent = userAgent - } - this.client = new PleromaAPI.Client(baseUrl, token, agent, proxyConfig) - this.baseUrl = baseUrl - } - - public cancel(): void { - return this.client.cancel() - } - - public async registerApp( - client_name: string, - options: Partial<{ scopes: Array; redirect_uris: string; website: string }> - ): Promise { - 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 - }) - }) - } - - /** - * Call /api/v1/apps - * - * Create an application. - * @param client_name your application's name - * @param options Form Data - */ - public async createApp( - client_name: string, - options: Partial<{ scopes: Array; redirect_uris: string; website: string }> - ): Promise { - const scopes = options.scopes || DEFAULT_SCOPE - const redirect_uris = options.redirect_uris || NO_REDIRECT - - const params: { - client_name: string - redirect_uris: string - scopes: string - website?: string - } = { - 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: Response) => OAuth.AppData.from(res.data)) - } - - /** - * Generate authorization url using OAuth2. - * - * @param clientId your OAuth app's client ID - * @param clientSecret your OAuth app's client Secret - * @param options as property, redirect_uri and scope are available, and must be the same as when you register your app - */ - public generateAuthUrl( - clientId: string, - clientSecret: string, - options: Partial<{ scope: Array; redirect_uri: string }> - ): Promise { - const scope = options.scope || DEFAULT_SCOPE - const redirect_uri = options.redirect_uri || NO_REDIRECT - return new Promise(resolve => { - const oauth = new OAuth2(clientId, clientSecret, this.baseUrl, undefined, '/oauth/token') - const url = oauth.getAuthorizeUrl({ - redirect_uri: redirect_uri, - response_type: 'code', - client_id: clientId, - scope: scope.join(' ') - }) - resolve(url) - }) - } - - // ====================================== - // apps - // ====================================== - public verifyAppCredentials(): Promise> { - return this.client.get('/api/v1/apps/verify_credentials') - } - - // ====================================== - // apps/oauth - // ====================================== - public async fetchAccessToken( - client_id: string | null, - client_secret: string, - code: string, - redirect_uri: string = NO_REDIRECT - ): Promise { - 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: Response) => OAuth.TokenData.from(res.data)) - } - - public async refreshToken(client_id: string, client_secret: string, refresh_token: string): Promise { - return this.client - .post('/oauth/token', { - client_id, - client_secret, - refresh_token, - grant_type: 'refresh_token' - }) - .then((res: Response) => OAuth.TokenData.from(res.data)) - } - - public async revokeToken(client_id: string, client_secret: string, token: string): Promise> { - return this.client.post<{}>('/oauth/revoke', { - client_id, - client_secret, - token - }) - } - - // ====================================== - // accounts - // ====================================== - public async registerAccount( - username: string, - email: string, - password: string, - agreement: boolean, - locale: string, - reason?: string | null - ): Promise> { - let params = { - username: username, - email: email, - password: password, - agreement: agreement, - locale: locale - } - if (reason) { - params = Object.assign(params, { - reason: reason - }) - } - return this.client.post('/api/v1/accounts', params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.token(res.data) - }) - }) - } - - public async verifyAccountCredentials(): Promise> { - return this.client.get('/api/v1/accounts/verify_credentials').then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.account(res.data) - }) - }) - } - - public async updateCredentials(options?: { - discoverable?: boolean - bot?: boolean - display_name?: string - note?: string - avatar?: string - header?: string - locked?: boolean - source?: { - privacy?: string - sensitive?: boolean - language?: string - } - fields_attributes?: Array<{ name: string; value: string }> - }): Promise> { - let params = {} - if (options) { - if (options.discoverable !== undefined) { - params = Object.assign(params, { - discoverable: options.discoverable - }) - } - if (options.bot !== undefined) { - params = Object.assign(params, { - bot: options.bot - }) - } - if (options.display_name) { - params = Object.assign(params, { - display_name: options.display_name - }) - } - if (options.note) { - params = Object.assign(params, { - note: options.note - }) - } - if (options.avatar) { - params = Object.assign(params, { - avatar: options.avatar - }) - } - if (options.header) { - params = Object.assign(params, { - header: options.header - }) - } - if (options.locked !== undefined) { - params = Object.assign(params, { - locked: options.locked - }) - } - if (options.source) { - params = Object.assign(params, { - source: options.source - }) - } - if (options.fields_attributes) { - params = Object.assign(params, { - fields_attributes: options.fields_attributes - }) - } - } - return this.client.patch('/api/v1/accounts/update_credentials', params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.account(res.data) - }) - }) - } - - public async getAccount(id: string): Promise> { - return this.client.get(`/api/v1/accounts/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.account(res.data) - }) - }) - } - - public async getAccountStatuses( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - pinned?: boolean - exclude_replies?: boolean - exclude_reblogs?: boolean - only_media?: boolean - } - ): Promise>> { - 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.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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - public async subscribeAccount(id: string): Promise> { - return this.client.post(`/api/v1/pleroma/accounts/${id}/subscribe`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async unsubscribeAccount(id: string): Promise> { - return this.client.post(`/api/v1/pleroma/accounts/${id}/unsubscribe`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async getAccountFavourites( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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/pleroma/accounts/${id}/favourites`, params).then(res => { - return Object.assign(res, { - data: res.data.map(s => PleromaAPI.Converter.status(s)) - }) - }) - } - - public async getAccountFollowers( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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.client.get>(`/api/v1/accounts/${id}/followers`, params).then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } - - public async getAccountFollowing( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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.client.get>(`/api/v1/accounts/${id}/following`, params).then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } - - public async getAccountLists(id: string): Promise>> { - return this.client.get>(`/api/v1/accounts/${id}/lists`).then(res => { - return Object.assign(res, { - data: res.data.map(l => PleromaAPI.Converter.list(l)) - }) - }) - } - - public async getIdentityProof(id: string): Promise>> { - return this.client.get>(`/api/v1/accounts/${id}/identity_proofs`).then(res => { - return Object.assign(res, { - data: res.data.map(i => PleromaAPI.Converter.identity_proof(i)) - }) - }) - } - - public async followAccount(id: string, options?: { reblog?: boolean }): Promise> { - 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: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async unfollowAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unfollow`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async blockAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/block`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async unblockAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unblock`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async muteAccount(id: string, notifications: boolean = true): Promise> { - return this.client - .post(`/api/v1/accounts/${id}/mute`, { - notifications: notifications - }) - .then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async unmuteAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unmute`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async pinAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/pin`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async unpinAccount(id: string): Promise> { - return this.client.post(`/api/v1/accounts/${id}/unpin`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async getRelationship(id: string): Promise> { - return this.client - .get>('/api/v1/accounts/relationships', { - id: [id] - }) - .then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data[0]) - }) - }) - } - - public async getRelationships(ids: Array): Promise>> { - return this.client - .get>('/api/v1/accounts/relationships', { - id: ids - }) - .then(res => { - return Object.assign(res, { - data: res.data.map(r => PleromaAPI.Converter.relationship(r)) - }) - }) - } - - public async searchAccount( - q: string, - options?: { - following?: boolean - resolve?: boolean - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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 => PleromaAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/bookmarks - // ====================================== - - public async getBookmarks(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - // ====================================== - // accounts/favourites - // ====================================== - - public async getFavourites(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - // ====================================== - // accounts/mutes - // ====================================== - - public async getMutes(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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 => PleromaAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/blocks - // ====================================== - - public async getBlocks(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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 => PleromaAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/domain_blocks - // ====================================== - public async getDomainBlocks(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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/domain_blocks', params) - } - - public blockDomain(domain: string): Promise> { - return this.client.post<{}>('/api/v1/domain_blocks', { - domain: domain - }) - } - - public unblockDomain(domain: string): Promise> { - return this.client.del<{}>('/api/v1/domain_blocks', { - domain: domain - }) - } - - // ====================================== - // accounts/filters - // ====================================== - - public async getFilters(): Promise>> { - return this.client.get>('/api/v1/filters').then(res => { - return Object.assign(res, { - data: res.data.map(f => PleromaAPI.Converter.filter(f)) - }) - }) - } - - public async getFilter(id: string): Promise> { - return this.client.get(`/api/v1/filters/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.filter(res.data) - }) - }) - } - - public async createFilter( - phrase: string, - context: Array, - options?: { - irreversible?: boolean - whole_word?: boolean - expires_in?: string - } - ): Promise> { - let params = { - phrase: phrase, - context: context - } - if (options) { - if (options.irreversible !== undefined) { - params = Object.assign(params, { - irreversible: options.irreversible - }) - } - if (options.whole_word !== undefined) { - params = Object.assign(params, { - whole_word: options.whole_word - }) - } - if (options.expires_in) { - params = Object.assign(params, { - expires_in: options.expires_in - }) - } - } - return this.client.post('/api/v1/filters', params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.filter(res.data) - }) - }) - } - - public async updateFilter( - id: string, - phrase: string, - context: Array, - options?: { - irreversible?: boolean - whole_word?: boolean - expires_in?: string - } - ): Promise> { - let params = { - phrase: phrase, - context: context - } - if (options) { - if (options.irreversible !== undefined) { - params = Object.assign(params, { - irreversible: options.irreversible - }) - } - if (options.whole_word !== undefined) { - params = Object.assign(params, { - whole_word: options.whole_word - }) - } - if (options.expires_in) { - params = Object.assign(params, { - expires_in: options.expires_in - }) - } - } - return this.client.put(`/api/v1/filters/${id}`, params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.filter(res.data) - }) - }) - } - - public async deleteFilter(id: string): Promise> { - return this.client.del(`/api/v1/filters/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.filter(res.data) - }) - }) - } - - // ====================================== - // accounts/reports - // ====================================== - public async report( - account_id: string, - comment: string, - options?: { - status_ids?: Array - - forward?: boolean - } - ): Promise> { - let params = { - account_id: account_id, - comment: comment - } - if (options) { - if (options.status_ids) { - params = Object.assign(params, { - status_ids: options.status_ids - }) - } - if (options.forward !== undefined) { - params = Object.assign(params, { - forward: options.forward - }) - } - } - return this.client.post('/api/v1/reports', params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.report(res.data) - }) - }) - } - - // ====================================== - // accounts/follow_requests - // ====================================== - public async getFollowRequests(limit?: number): Promise>> { - if (limit) { - return this.client - .get>('/api/v1/follow_requests', { - limit: limit - }) - .then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } else { - return this.client.get>('/api/v1/follow_requests').then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } - } - - public async acceptFollowRequest(id: string): Promise> { - return this.client.post(`/api/v1/follow_requests/${id}/authorize`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - public async rejectFollowRequest(id: string): Promise> { - return this.client.post(`/api/v1/follow_requests/${id}/reject`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.relationship(res.data) - }) - }) - } - - // ====================================== - // accounts/endorsements - // ====================================== - public async getEndorsements(options?: { limit?: number; max_id?: string; since_id?: string }): Promise>> { - 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 => PleromaAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // accounts/featured_tags - // ====================================== - public async getFeaturedTags(): Promise>> { - return this.client.get>('/api/v1/featured_tags').then(res => { - return Object.assign(res, { - data: res.data.map(f => PleromaAPI.Converter.featured_tag(f)) - }) - }) - } - - public async getAccountFeaturedTags(id: string): Promise>> { - return this.client.get>(`/api/v1/accounts/${id}/featured_tags`).then(res => { - return Object.assign(res, { - data: res.data.map(f => PleromaAPI.Converter.featured_tag(f)) - }) - }) - } - - public async createFeaturedTag(name: string): Promise> { - return this.client - .post('/api/v1/featured_tags', { - name: name - }) - .then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.featured_tag(res.data) - }) - }) - } - - public deleteFeaturedTag(id: string): Promise> { - return this.client.del<{}>(`/api/v1/featured_tags/${id}`) - } - - public async getSuggestedTags(): Promise>> { - return this.client.get>('/api/v1/featured_tags/suggestions').then(res => { - return Object.assign(res, { - data: res.data.map(t => PleromaAPI.Converter.tag(t)) - }) - }) - } - - // ====================================== - // accounts/preferences - // ====================================== - public async getPreferences(): Promise> { - return this.client.get('/api/v1/preferences').then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.preferences(res.data) - }) - }) - } - - // ====================================== - // accounts/suggestions - // ====================================== - public async getSuggestions(limit?: number): Promise>> { - if (limit) { - return this.client - .get>('/api/v1/suggestions', { - limit: limit - }) - .then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } else { - return this.client.get>('/api/v1/suggestions').then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } - } - - // ====================================== - // accounts/tags - // ====================================== - public async getTag(id: string): Promise> { - return this.client.get(`/api/v1/tags/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.tag(res.data) - }) - }) - } - - public async followTag(id: string): Promise> { - return this.client.post(`/api/v1/tags/${id}/follow`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.tag(res.data) - }) - }) - } - - public async unfollowTag(id: string): Promise> { - return this.client.post(`/api/v1/tags/${id}/unfollow`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.tag(res.data) - }) - }) - } - - // ====================================== - // statuses - // ====================================== - public async postStatus( - status: string, - options: { - media_ids?: Array - poll?: { options: Array; expires_in: number; multiple?: boolean; hide_totals?: boolean } - in_reply_to_id?: string - sensitive?: boolean - spoiler_text?: string - visibility?: 'public' | 'unlisted' | 'private' | 'direct' - scheduled_at?: string - language?: string - } - ): Promise> { - 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: 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 - }) - } - } - return this.client.post('/api/v1/statuses', params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async getStatus(id: string): Promise> { - return this.client.get(`/api/v1/statuses/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async editStatus( - id: string, - options: { - status?: string - spoiler_text?: string - sensitive?: boolean - media_ids?: Array - poll?: { options?: Array; expires_in?: number; multiple?: boolean; hide_totals?: boolean } - } - ): Promise> { - 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: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async deleteStatus(id: string): Promise> { - return this.client.del(`/api/v1/statuses/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async getStatusContext( - id: string, - options?: { limit?: number; max_id?: string; since_id?: string } - ): Promise> { - 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: PleromaAPI.Converter.context(res.data) - }) - }) - } - - public async getStatusRebloggedBy(id: string): Promise>> { - return this.client.get>(`/api/v1/statuses/${id}/reblogged_by`).then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } - - public async getStatusFavouritedBy(id: string): Promise>> { - return this.client.get>(`/api/v1/statuses/${id}/favourited_by`).then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.account(a)) - }) - }) - } - - public async favouriteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/favourite`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async unfavouriteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unfavourite`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async reblogStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/reblog`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async unreblogStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unreblog`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async bookmarkStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/bookmark`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async unbookmarkStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unbookmark`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async muteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/mute`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async unmuteStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unmute`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async pinStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/pin`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - public async unpinStatus(id: string): Promise> { - return this.client.post(`/api/v1/statuses/${id}/unpin`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - // ====================================== - // statuses/media - // ====================================== - public async uploadMedia( - file: any, - options?: { description?: string; focus?: string } - ): Promise> { - 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: PleromaAPI.Converter.async_attachment(res.data) - }) - }) - } - - public async getMedia(id: string): Promise> { - const res = await this.client.get(`/api/v1/media/${id}`) - - return Object.assign(res, { - data: PleromaAPI.Converter.attachment(res.data) - }) - } - - public async updateMedia( - id: string, - options?: { - file?: any - description?: string - focus?: string - } - ): Promise> { - 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: PleromaAPI.Converter.attachment(res.data) - }) - }) - } - - // ====================================== - // statuses/polls - // ====================================== - public async getPoll(id: string): Promise> { - return this.client.get(`/api/v1/polls/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.poll(res.data) - }) - }) - } - - public async votePoll(id: string, choices: Array): Promise> { - return this.client - .post(`/api/v1/polls/${id}/votes`, { - choices: choices - }) - .then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.poll(res.data) - }) - }) - } - - // ====================================== - // statuses/scheduled_statuses - // ====================================== - public async getScheduledStatuses(options?: { - limit?: number | null - max_id?: string | null - since_id?: string | null - min_id?: string | null - }): Promise>> { - 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 => PleromaAPI.Converter.scheduled_status(s)) - }) - }) - } - - public async getScheduledStatus(id: string): Promise> { - return this.client.get(`/api/v1/scheduled_statuses/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.scheduled_status(res.data) - }) - }) - } - - public async scheduleStatus(id: string, scheduled_at?: string | null): Promise> { - let params = {} - if (scheduled_at) { - params = Object.assign(params, { - scheduled_at: scheduled_at - }) - } - return this.client.put(`/api/v1/scheduled_statuses/${id}`, params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.scheduled_status(res.data) - }) - }) - } - - public cancelScheduledStatus(id: string): Promise> { - return this.client.del<{}>(`/api/v1/scheduled_statuses/${id}`) - } - - // ====================================== - // timelines - // ====================================== - public async getPublicTimeline(options?: { - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - public async getLocalTimeline(options?: { - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - public async getTagTimeline( - hashtag: string, - options?: { - local?: boolean - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - } - ): Promise>> { - 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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - public async getHomeTimeline(options?: { - local?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - public async getListTimeline( - list_id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - } - ): Promise>> { - 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 => PleromaAPI.Converter.status(s)) - }) - }) - } - - // ====================================== - // timelines/conversations - // ====================================== - public async getConversationTimeline(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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 => PleromaAPI.Converter.conversation(c)) - }) - }) - } - - public deleteConversation(id: string): Promise> { - return this.client.del<{}>(`/api/v1/conversations/${id}`) - } - - public async readConversation(id: string): Promise> { - return this.client.post(`/api/v1/conversations/${id}/read`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.conversation(res.data) - }) - }) - } - - // ====================================== - // timelines/lists - // ====================================== - public async getLists(): Promise>> { - return this.client.get>('/api/v1/lists').then(res => { - return Object.assign(res, { - data: res.data.map(l => PleromaAPI.Converter.list(l)) - }) - }) - } - - public async getList(id: string): Promise> { - return this.client.get(`/api/v1/lists/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.list(res.data) - }) - }) - } - - public async createList(title: string): Promise> { - return this.client - .post('/api/v1/lists', { - title: title - }) - .then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.list(res.data) - }) - }) - } - - public async updateList(id: string, title: string): Promise> { - return this.client - .put(`/api/v1/lists/${id}`, { - title: title - }) - .then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.list(res.data) - }) - }) - } - - public deleteList(id: string): Promise> { - return this.client.del<{}>(`/api/v1/lists/${id}`) - } - - public async getAccountsInList( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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 => PleromaAPI.Converter.account(a)) - }) - }) - } - - public addAccountsToList(id: string, account_ids: Array): Promise> { - return this.client.post<{}>(`/api/v1/lists/${id}/accounts`, { - account_ids: account_ids - }) - } - - public deleteAccountsFromList(id: string, account_ids: Array): Promise> { - return this.client.del<{}>(`/api/v1/lists/${id}/accounts`, { - account_ids: account_ids - }) - } - - // ====================================== - // timelines/markers - // ====================================== - public async getMarkers(timeline: Array): Promise> { - return this.client.get('/api/v1/markers', { - timeline: timeline - }) - } - - public async saveMarkers(options?: { - home?: { last_read_id: string } - notifications?: { last_read_id: string } - }): Promise> { - let params = {} - if (options) { - if (options.home) { - params = Object.assign(params, { - home: options.home - }) - } - if (options.notifications) { - params = Object.assign(params, { - notifications: options.notifications - }) - } - } - return this.client.post('/api/v1/markers', params).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.marker(res.data) - }) - }) - } - - // ====================================== - // notifications - // ====================================== - public async getNotifications(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - exclude_types?: Array - account_id?: string - }): Promise>> { - 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 => PleromaAPI.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.map(n => PleromaAPI.Converter.notification(n)) - }) - }) - } - - public async getNotification(id: string): Promise> { - return this.client.get(`/api/v1/notifications/${id}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.notification(res.data) - }) - }) - } - - public dismissNotifications(): Promise> { - return this.client.post<{}>('/api/v1/notifications/clear') - } - - public dismissNotification(id: string): Promise> { - return this.client.post<{}>(`/api/v1/notifications/${id}/dismiss`) - } - - public async readNotifications(options: { - id?: string - max_id?: string - }): Promise>> { - if (options.id) { - return this.client - .post('/api/v1/pleroma/notifications/read', { - id: options.id - }) - .then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.notification(res.data) - }) - }) - } else if (options.max_id) { - return this.client - .post>('/api/v1/pleroma/notifications/read', { - max_id: options.max_id - }) - .then(res => { - return Object.assign(res, { - data: res.data.map(n => PleromaAPI.Converter.notification(n)) - }) - }) - } else { - return new Promise((_, reject) => { - const err = new ArgumentError('id or max_id is required') - reject(err) - }) - } - } - - // ====================================== - // notifications/push - // ====================================== - public async subscribePushNotification( - subscription: { endpoint: string; keys: { p256dh: string; auth: string } }, - data?: { alerts: { follow?: boolean; favourite?: boolean; reblog?: boolean; mention?: boolean; poll?: boolean } } | null - ): Promise> { - 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: PleromaAPI.Converter.push_subscription(res.data) - }) - }) - } - - public async getPushSubscription(): Promise> { - return this.client.get('/api/v1/push/subscription').then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.push_subscription(res.data) - }) - }) - } - - public async updatePushSubscription( - data?: { alerts: { follow?: boolean; favourite?: boolean; reblog?: boolean; mention?: boolean; poll?: boolean } } | null - ): Promise> { - 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: PleromaAPI.Converter.push_subscription(res.data) - }) - }) - } - - public deletePushSubscription(): Promise> { - return this.client.del<{}>('/api/v1/push/subscription') - } - - // ====================================== - // search - // ====================================== - public async search( - q: string, - type: 'accounts' | 'hashtags' | 'statuses', - options?: { - limit?: number - max_id?: string - min_id?: string - resolve?: boolean - offset?: number - following?: boolean - account_id?: string - exclude_unreviewed?: boolean - } - ): Promise> { - let params = { - q, - type - } - 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.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: PleromaAPI.Converter.results(res.data) - }) - }) - } - - // ====================================== - // instance - // ====================================== - public async getInstance(): Promise> { - return this.client.get('/api/v1/instance').then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.instance(res.data) - }) - }) - } - - public getInstancePeers(): Promise>> { - return this.client.get>('/api/v1/instance/peers') - } - - public async getInstanceActivity(): Promise>> { - return this.client.get>('/api/v1/instance/activity').then(res => { - return Object.assign(res, { - data: res.data.map(a => PleromaAPI.Converter.activity(a)) - }) - }) - } - - // ====================================== - // instance/trends - // ====================================== - /** - * GET /api/v1/trends - * - * @param limit Maximum number of results to return. Defaults to 10. - */ - public async getInstanceTrends(limit?: number | null): Promise>> { - 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 => PleromaAPI.Converter.tag(t)) - }) - }) - } - - // ====================================== - // instance/directory - // ====================================== - public async getInstanceDirectory(options?: { - limit?: number - offset?: number - order?: 'active' | 'new' - local?: boolean - }): Promise>> { - 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 => PleromaAPI.Converter.account(a)) - }) - }) - } - - // ====================================== - // instance/custom_emojis - // ====================================== - public async getInstanceCustomEmojis(): Promise>> { - return this.client.get>('/api/v1/custom_emojis').then(res => { - return Object.assign(res, { - data: res.data.map(e => PleromaAPI.Converter.emoji(e)) - }) - }) - } - - // ====================================== - // instance/announcements - // ====================================== - public async getInstanceAnnouncements(with_dismissed?: boolean | null): Promise>> { - let params = {} - if (with_dismissed) { - params = Object.assign(params, { - with_dismissed - }) - } - return this.client.get>('/api/v1/announcements', params).then(res => ({ - ...res, - data: res.data.map(t => PleromaAPI.Converter.announcement(t)) - })) - } - - public async dismissInstanceAnnouncement(id: string): Promise> { - return this.client.post<{}>(`/api/v1/announcements/${id}/dismiss`) - } - - // ====================================== - // Emoji reactions - // ====================================== - /** - * PUT /api/v1/pleroma/statuses/:status_id/reactions/:emoji - * - * @param {string} id Target status ID. - * @param {string} emoji Reaction emoji string. This string is raw unicode emoji. - */ - public async createEmojiReaction(id: string, emoji: string): Promise> { - return this.client.put(`/api/v1/pleroma/statuses/${id}/reactions/${encodeURI(emoji)}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - /** - * DELETE /api/v1/pleroma/statuses/:status_id/reactions/:emoji - * - * @param {string} id Target status ID. - * @param {string} emoji Reaction emoji string. This string is raw unicode emoji. - */ - public async deleteEmojiReaction(id: string, emoji: string): Promise> { - return this.client.del(`/api/v1/pleroma/statuses/${id}/reactions/${encodeURI(emoji)}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.status(res.data) - }) - }) - } - - /** - * GET /api/v1/pleroma/statuses/:status_id/reactions - * - * @param {string} id Target status ID. - */ - public async getEmojiReactions(id: string): Promise>> { - return this.client.get>(`/api/v1/pleroma/statuses/${id}/reactions`).then(res => { - return Object.assign(res, { - data: res.data.map(r => PleromaAPI.Converter.reaction(r)) - }) - }) - } - - /** - * GET /api/v1/pleroma/statuses/:status_id/reactions/:emoji - * - * @param {string} id Target status ID. - * @param {string} emoji Reaction emoji string. This string is url encoded unicode emoji. - */ - public async getEmojiReaction(id: string, emoji: string): Promise> { - return this.client.get(`/api/v1/pleroma/statuses/${id}/reactions/${encodeURI(emoji)}`).then(res => { - return Object.assign(res, { - data: PleromaAPI.Converter.reaction(res.data) - }) - }) - } - - // ====================================== - // WebSocket - // ====================================== - public userSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'user') - } - - public publicSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'public') - } - - public localSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'public:local') - } - - public tagSocket(tag: string): WebSocket { - return this.client.socket('/api/v1/streaming', 'hashtag', `tag=${tag}`) - } - - public listSocket(list_id: string): WebSocket { - return this.client.socket('/api/v1/streaming', 'list', `list=${list_id}`) - } - - public directSocket(): WebSocket { - return this.client.socket('/api/v1/streaming', 'direct') - } -} diff --git a/megalodon/src/pleroma/api_client.ts b/megalodon/src/pleroma/api_client.ts deleted file mode 100644 index e965d3e..0000000 --- a/megalodon/src/pleroma/api_client.ts +++ /dev/null @@ -1,670 +0,0 @@ -import axios, { AxiosResponse, AxiosRequestConfig } from 'axios' -import objectAssignDeep from 'object-assign-deep' - -import MegalodonEntity from '../entity' -import PleromaEntity from './entity' -import Response from '../response' -import { RequestCanceledError } from '../cancel' -import proxyAgent, { ProxyConfig } from '../proxy_config' -import { NO_REDIRECT, DEFAULT_SCOPE, DEFAULT_UA } from '../default' -import WebSocket from './web_socket' -import NotificationType from '../notification' -import PleromaNotificationType from './notification' - -namespace PleromaAPI { - export namespace Entity { - export type Account = PleromaEntity.Account - export type Activity = PleromaEntity.Activity - export type Announcement = PleromaEntity.Announcement - export type Application = PleromaEntity.Application - export type AsyncAttachment = PleromaEntity.AsyncAttachment - export type Attachment = PleromaEntity.Attachment - export type Card = PleromaEntity.Card - export type Context = PleromaEntity.Context - export type Conversation = PleromaEntity.Conversation - export type Emoji = PleromaEntity.Emoji - export type FeaturedTag = PleromaEntity.FeaturedTag - export type Field = PleromaEntity.Field - export type Filter = PleromaEntity.Filter - export type History = PleromaEntity.History - export type IdentityProof = PleromaEntity.IdentityProof - export type Instance = PleromaEntity.Instance - export type List = PleromaEntity.List - export type Marker = PleromaEntity.Marker - export type Mention = PleromaEntity.Mention - export type Notification = PleromaEntity.Notification - export type Poll = PleromaEntity.Poll - export type PollOption = PleromaEntity.PollOption - export type Preferences = PleromaEntity.Preferences - export type PushSubscription = PleromaEntity.PushSubscription - export type Reaction = PleromaEntity.Reaction - export type Relationship = PleromaEntity.Relationship - export type Report = PleromaEntity.Report - export type Results = PleromaEntity.Results - export type ScheduledStatus = PleromaEntity.ScheduledStatus - export type Source = PleromaEntity.Source - export type Stats = PleromaEntity.Stats - export type Status = PleromaEntity.Status - export type StatusParams = PleromaEntity.StatusParams - export type Tag = PleromaEntity.Tag - export type Token = PleromaEntity.Token - export type URLs = PleromaEntity.URLs - } - - export namespace Converter { - export const decodeNotificationType = (t: PleromaEntity.NotificationType): MegalodonEntity.NotificationType => { - switch (t) { - case PleromaNotificationType.Mention: - return NotificationType.Mention - case PleromaNotificationType.Reblog: - return NotificationType.Reblog - case PleromaNotificationType.Favourite: - return NotificationType.Favourite - case PleromaNotificationType.Follow: - return NotificationType.Follow - case PleromaNotificationType.Poll: - return NotificationType.PollExpired - case PleromaNotificationType.PleromaEmojiReaction: - return NotificationType.EmojiReaction - case PleromaNotificationType.FollowRequest: - return NotificationType.FollowRequest - default: - return t - } - } - export const encodeNotificationType = (t: MegalodonEntity.NotificationType): PleromaEntity.NotificationType => { - switch (t) { - case NotificationType.Follow: - return PleromaNotificationType.Follow - case NotificationType.Favourite: - return PleromaNotificationType.Favourite - case NotificationType.Reblog: - return PleromaNotificationType.Reblog - case NotificationType.Mention: - return PleromaNotificationType.Mention - case NotificationType.PollExpired: - return PleromaNotificationType.Poll - case NotificationType.EmojiReaction: - return PleromaNotificationType.PleromaEmojiReaction - case NotificationType.FollowRequest: - return PleromaNotificationType.FollowRequest - default: - return t - } - } - - export const account = (a: Entity.Account): MegalodonEntity.Account => a - export const activity = (a: Entity.Activity): MegalodonEntity.Activity => a - export const announcement = (a: Entity.Announcement): MegalodonEntity.Announcement => a - export const application = (a: Entity.Application): MegalodonEntity.Application => a - export const attachment = (a: Entity.Attachment): MegalodonEntity.Attachment => a - export const async_attachment = (a: Entity.AsyncAttachment) => { - if (a.url) { - return { - id: a.id, - type: a.type, - url: a.url!, - remote_url: a.remote_url, - preview_url: a.preview_url, - text_url: a.text_url, - meta: a.meta, - description: a.description, - blurhash: a.blurhash - } as MegalodonEntity.Attachment - } else { - return a as MegalodonEntity.AsyncAttachment - } - } - export const card = (c: Entity.Card): MegalodonEntity.Card => c - export const context = (c: Entity.Context): MegalodonEntity.Context => ({ - ancestors: c.ancestors.map(a => status(a)), - descendants: c.descendants.map(d => status(d)) - }) - export const conversation = (c: Entity.Conversation): MegalodonEntity.Conversation => ({ - id: c.id, - accounts: c.accounts.map(a => account(a)), - last_status: c.last_status ? status(c.last_status) : null, - unread: c.unread - }) - export const emoji = (e: Entity.Emoji): MegalodonEntity.Emoji => e - export const featured_tag = (f: Entity.FeaturedTag): MegalodonEntity.FeaturedTag => f - export const field = (f: Entity.Field): MegalodonEntity.Field => f - export const filter = (f: Entity.Filter): MegalodonEntity.Filter => f - export const history = (h: Entity.History): MegalodonEntity.History => h - export const identity_proof = (i: Entity.IdentityProof): MegalodonEntity.IdentityProof => i - export const instance = (i: Entity.Instance): MegalodonEntity.Instance => i - export const list = (l: Entity.List): MegalodonEntity.List => l - export const marker = (m: Entity.Marker): MegalodonEntity.Marker => { - return { - notifications: { - last_read_id: m.notifications.last_read_id, - version: m.notifications.version, - updated_at: m.notifications.updated_at, - unread_count: m.notifications.pleroma.unread_count - } - } - } - export const mention = (m: Entity.Mention): MegalodonEntity.Mention => m - export const notification = (n: Entity.Notification): MegalodonEntity.Notification => { - if (n.status && n.emoji) { - return { - id: n.id, - account: n.account, - created_at: n.created_at, - status: status(n.status), - emoji: n.emoji, - type: decodeNotificationType(n.type) - } - } else if (n.status) { - return { - id: n.id, - account: n.account, - created_at: n.created_at, - status: status(n.status), - type: decodeNotificationType(n.type) - } - } else { - return { - id: n.id, - account: n.account, - created_at: n.created_at, - type: decodeNotificationType(n.type) - } - } - } - export const poll = (p: Entity.Poll): MegalodonEntity.Poll => p - export const pollOption = (p: Entity.PollOption): MegalodonEntity.PollOption => p - export const preferences = (p: Entity.Preferences): MegalodonEntity.Preferences => p - export const push_subscription = (p: Entity.PushSubscription): MegalodonEntity.PushSubscription => p - export const reaction = (r: Entity.Reaction): MegalodonEntity.Reaction => r - export const relationship = (r: Entity.Relationship): MegalodonEntity.Relationship => ({ - id: r.id, - following: r.following, - followed_by: r.followed_by, - blocking: r.blocking, - blocked_by: r.blocked_by, - muting: r.muting, - muting_notifications: r.muting_notifications, - requested: r.requested, - domain_blocking: r.domain_blocking, - showing_reblogs: r.showing_reblogs, - endorsed: r.endorsed, - notifying: r.subscribing - }) - export const report = (r: Entity.Report): MegalodonEntity.Report => r - export const results = (r: Entity.Results): MegalodonEntity.Results => ({ - accounts: r.accounts.map(a => account(a)), - statuses: r.statuses.map(s => status(s)), - hashtags: r.hashtags.map(h => tag(h)) - }) - export const scheduled_status = (s: Entity.ScheduledStatus): MegalodonEntity.ScheduledStatus => ({ - id: s.id, - scheduled_at: s.scheduled_at, - params: s.params, - media_attachments: s.media_attachments.map(m => attachment(m)) - }) - export const source = (s: Entity.Source): MegalodonEntity.Source => s - export const stats = (s: Entity.Stats): MegalodonEntity.Stats => s - export const status = (s: Entity.Status): MegalodonEntity.Status => ({ - id: s.id, - uri: s.uri, - url: s.url, - account: account(s.account), - in_reply_to_id: s.in_reply_to_id, - in_reply_to_account_id: s.in_reply_to_account_id, - reblog: s.reblog ? status(s.reblog) : null, - content: s.content, - plain_content: s.pleroma.content?.['text/plain'] ? s.pleroma.content['text/plain'] : null, - created_at: s.created_at, - emojis: s.emojis.map(e => emoji(e)), - replies_count: s.replies_count, - reblogs_count: s.reblogs_count, - favourites_count: s.favourites_count, - reblogged: s.reblogged, - favourited: s.favourited, - muted: s.muted, - sensitive: s.sensitive, - spoiler_text: s.spoiler_text, - visibility: s.visibility, - media_attachments: s.media_attachments.map(m => attachment(m)), - mentions: s.mentions.map(m => mention(m)), - tags: s.tags.map(t => tag(t)), - card: s.card ? card(s.card) : null, - poll: s.poll ? poll(s.poll) : null, - application: s.application ? application(s.application) : null, - language: s.language, - pinned: s.pinned, - emoji_reactions: s.pleroma.emoji_reactions ? s.pleroma.emoji_reactions.map(r => reaction(r)) : [], - bookmarked: s.bookmarked ? s.bookmarked : false, - quote: null - }) - export const status_params = (s: Entity.StatusParams): MegalodonEntity.StatusParams => s - export const tag = (t: Entity.Tag): MegalodonEntity.Tag => t - export const token = (t: Entity.Token): MegalodonEntity.Token => t - export const urls = (u: Entity.URLs): MegalodonEntity.URLs => u - } - - /** - * Interface - */ - export interface Interface { - get(path: string, params?: any, headers?: { [key: string]: string }): Promise> - put(path: string, params?: any, headers?: { [key: string]: string }): Promise> - putForm(path: string, params?: any, headers?: { [key: string]: string }): Promise> - patch(path: string, params?: any, headers?: { [key: string]: string }): Promise> - patchForm(path: string, params?: any, headers?: { [key: string]: string }): Promise> - post(path: string, params?: any, headers?: { [key: string]: string }): Promise> - postForm(path: string, params?: any, headers?: { [key: string]: string }): Promise> - del(path: string, params?: any, headers?: { [key: string]: string }): Promise> - cancel(): void - socket(path: string, stream: string, params?: string): WebSocket - } - - /** - * Mastodon API client. - * - * Using axios for request, you will handle promises. - */ - export class Client implements Interface { - static DEFAULT_SCOPE = DEFAULT_SCOPE - static DEFAULT_URL = 'https://pleroma.io' - static NO_REDIRECT = NO_REDIRECT - - private accessToken: string | null - private baseUrl: string - private userAgent: string - private abortController: AbortController - private proxyConfig: ProxyConfig | false = false - - /** - * @param baseUrl hostname or base URL - * @param accessToken access token from OAuth2 authorization - * @param userAgent UserAgent is specified in header on request. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor( - baseUrl: string, - accessToken: string | null = null, - userAgent: string = DEFAULT_UA, - proxyConfig: ProxyConfig | false = false - ) { - this.accessToken = accessToken - this.baseUrl = baseUrl - this.userAgent = userAgent - this.proxyConfig = proxyConfig - this.abortController = new AbortController() - axios.defaults.signal = this.abortController.signal - } - - /** - * GET request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Query parameters - * @param headers Request header object - */ - public async get(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - params: params, - headers: headers - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .get(this.baseUrl + path, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PUT request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async put(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .put(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PUT request to mastodon REST API for multipart. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async putForm(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .putForm(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PATCH request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async patch(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .patch(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * PATCH request to mastodon REST API for multipart. - * @param path relative path from baseUrl - * @param params Form data. If you want to post file, please use FormData() - * @param headers Request header object - */ - public async patchForm(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .patchForm(this.baseUrl + path, params, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * POST request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data - * @param headers Request header object - */ - public async post(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios.post(this.baseUrl + path, params, options).then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * POST request to mastodon REST API for multipart. - * @param path relative path from baseUrl - * @param params Form data - * @param headers Request header object - */ - public async postForm(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios.postForm(this.baseUrl + path, params, options).then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * DELETE request to mastodon REST API. - * @param path relative path from baseUrl - * @param params Form data - * @param headers Request header object - */ - public async del(path: string, params = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - data: params, - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.accessToken) { - options = objectAssignDeep({}, options, { - headers: { - Authorization: `Bearer ${this.accessToken}` - } - }) - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios - .delete(this.baseUrl + path, options) - .catch((err: Error) => { - if (axios.isCancel(err)) { - throw new RequestCanceledError(err.message) - } else { - throw err - } - }) - .then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * Cancel all requests in this instance. - * @returns void - */ - public cancel(): void { - return this.abortController.abort() - } - - /** - * Get connection and receive websocket connection for Pleroma API. - * - * @param path relative path from baseUrl: normally it is `/streaming`. - * @param stream Stream name, please refer: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/mastodon_api/mastodon_socket.ex#L19-28 - * @returns WebSocket, which inherits from EventEmitter - */ - public socket(path: string, stream: string, params?: string): WebSocket { - if (!this.accessToken) { - throw new Error('accessToken is required') - } - const url = this.baseUrl + path - const streaming = new WebSocket(url, stream, params, this.accessToken, this.userAgent, this.proxyConfig) - process.nextTick(() => { - streaming.start() - }) - return streaming - } - } -} - -export default PleromaAPI diff --git a/megalodon/src/pleroma/entities/account.ts b/megalodon/src/pleroma/entities/account.ts deleted file mode 100644 index 02ee0b7..0000000 --- a/megalodon/src/pleroma/entities/account.ts +++ /dev/null @@ -1,27 +0,0 @@ -/// -/// -/// -namespace PleromaEntity { - export type Account = { - id: string - username: string - acct: string - display_name: string - locked: boolean - created_at: string - followers_count: number - following_count: number - statuses_count: number - note: string - url: string - avatar: string - avatar_static: string - header: string - header_static: string - emojis: Array - moved: Account | null - fields: Array - bot: boolean | null - source?: Source - } -} diff --git a/megalodon/src/pleroma/entities/activity.ts b/megalodon/src/pleroma/entities/activity.ts deleted file mode 100644 index f70ad16..0000000 --- a/megalodon/src/pleroma/entities/activity.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace PleromaEntity { - export type Activity = { - week: string - statuses: string - logins: string - registrations: string - } -} diff --git a/megalodon/src/pleroma/entities/announcement.ts b/megalodon/src/pleroma/entities/announcement.ts deleted file mode 100644 index 72417af..0000000 --- a/megalodon/src/pleroma/entities/announcement.ts +++ /dev/null @@ -1,34 +0,0 @@ -/// -/// -/// - -namespace PleromaEntity { - export type Announcement = { - id: string - content: string - starts_at: string | null - ends_at: string | null - published: boolean - all_day: boolean - published_at: string - updated_at: string - read?: boolean - mentions: Array - statuses: Array - tags: Array - emojis: Array - reactions: Array - } - - export type AnnouncementAccount = { - id: string - username: string - url: string - acct: string - } - - export type AnnouncementStatus = { - id: string - url: string - } -} diff --git a/megalodon/src/pleroma/entities/application.ts b/megalodon/src/pleroma/entities/application.ts deleted file mode 100644 index 055592d..0000000 --- a/megalodon/src/pleroma/entities/application.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace PleromaEntity { - export type Application = { - name: string - website?: string | null - vapid_key?: string | null - } -} diff --git a/megalodon/src/pleroma/entities/async_attachment.ts b/megalodon/src/pleroma/entities/async_attachment.ts deleted file mode 100644 index 8784979..0000000 --- a/megalodon/src/pleroma/entities/async_attachment.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// -namespace PleromaEntity { - export type AsyncAttachment = { - id: string - type: 'unknown' | 'image' | 'gifv' | 'video' | 'audio' - url: string | null - remote_url: string | null - preview_url: string - text_url: string | null - meta: Meta | null - description: string | null - blurhash: string | null - } -} diff --git a/megalodon/src/pleroma/entities/attachment.ts b/megalodon/src/pleroma/entities/attachment.ts deleted file mode 100644 index 18d4371..0000000 --- a/megalodon/src/pleroma/entities/attachment.ts +++ /dev/null @@ -1,49 +0,0 @@ -namespace PleromaEntity { - export type Sub = { - // For Image, Gifv, and Video - width?: number - height?: number - size?: string - aspect?: number - - // For Gifv and Video - frame_rate?: string - - // For Audio, Gifv, and Video - duration?: number - bitrate?: number - } - - export type Focus = { - x: number - y: number - } - - export type Meta = { - original?: Sub - small?: Sub - focus?: Focus - length?: string - duration?: number - fps?: number - size?: string - width?: number - height?: number - aspect?: number - audio_encode?: string - audio_bitrate?: string - audio_channel?: string - } - - export type Attachment = { - id: string - type: 'unknown' | 'image' | 'gifv' | 'video' | 'audio' - url: string - remote_url: string | null - preview_url: string | null - text_url: string | null - meta: Meta | null - description: string | null - blurhash: string | null - } -} diff --git a/megalodon/src/pleroma/entities/card.ts b/megalodon/src/pleroma/entities/card.ts deleted file mode 100644 index 28d2013..0000000 --- a/megalodon/src/pleroma/entities/card.ts +++ /dev/null @@ -1,17 +0,0 @@ -namespace PleromaEntity { - export type Card = { - url: string - title: string - description: string - type: 'link' | 'photo' | 'video' | 'rich' - image?: string - author_name?: string - author_url?: string - provider_name?: string - provider_url?: string - html?: string - width?: number - height?: number - pleroma?: Object - } -} diff --git a/megalodon/src/pleroma/entities/context.ts b/megalodon/src/pleroma/entities/context.ts deleted file mode 100644 index f297bd2..0000000 --- a/megalodon/src/pleroma/entities/context.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -namespace PleromaEntity { - export type Context = { - ancestors: Array - descendants: Array - } -} diff --git a/megalodon/src/pleroma/entities/conversation.ts b/megalodon/src/pleroma/entities/conversation.ts deleted file mode 100644 index 624e6da..0000000 --- a/megalodon/src/pleroma/entities/conversation.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// -/// - -namespace PleromaEntity { - export type Conversation = { - id: string - accounts: Array - last_status: Status | null - unread: boolean - } -} diff --git a/megalodon/src/pleroma/entities/emoji.ts b/megalodon/src/pleroma/entities/emoji.ts deleted file mode 100644 index 8734276..0000000 --- a/megalodon/src/pleroma/entities/emoji.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace PleromaEntity { - export type Emoji = { - shortcode: string - static_url: string - url: string - visible_in_picker: boolean - category: string - } -} diff --git a/megalodon/src/pleroma/entities/featured_tag.ts b/megalodon/src/pleroma/entities/featured_tag.ts deleted file mode 100644 index a42e27f..0000000 --- a/megalodon/src/pleroma/entities/featured_tag.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace PleromaEntity { - export type FeaturedTag = { - id: string - name: string - statuses_count: number - last_status_at: string - } -} diff --git a/megalodon/src/pleroma/entities/field.ts b/megalodon/src/pleroma/entities/field.ts deleted file mode 100644 index 0180307..0000000 --- a/megalodon/src/pleroma/entities/field.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace PleromaEntity { - export type Field = { - name: string - value: string - verified_at: string | null - } -} diff --git a/megalodon/src/pleroma/entities/filter.ts b/megalodon/src/pleroma/entities/filter.ts deleted file mode 100644 index 08a1808..0000000 --- a/megalodon/src/pleroma/entities/filter.ts +++ /dev/null @@ -1,12 +0,0 @@ -namespace PleromaEntity { - export type Filter = { - id: string - phrase: string - context: Array - expires_at: string | null - irreversible: boolean - whole_word: boolean - } - - export type FilterContext = string -} diff --git a/megalodon/src/pleroma/entities/history.ts b/megalodon/src/pleroma/entities/history.ts deleted file mode 100644 index 9aaaeb8..0000000 --- a/megalodon/src/pleroma/entities/history.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace PleromaEntity { - export type History = { - day: string - uses: number - accounts: number - } -} diff --git a/megalodon/src/pleroma/entities/identity_proof.ts b/megalodon/src/pleroma/entities/identity_proof.ts deleted file mode 100644 index 463fdc6..0000000 --- a/megalodon/src/pleroma/entities/identity_proof.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace PleromaEntity { - export type IdentityProof = { - provider: string - provider_username: string - updated_at: string - proof_url: string - profile_url: string - } -} diff --git a/megalodon/src/pleroma/entities/instance.ts b/megalodon/src/pleroma/entities/instance.ts deleted file mode 100644 index 472b62b..0000000 --- a/megalodon/src/pleroma/entities/instance.ts +++ /dev/null @@ -1,41 +0,0 @@ -/// -/// -/// - -namespace PleromaEntity { - export type Instance = { - uri: string - title: string - description: string - email: string - version: string - thumbnail: string | null - urls: URLs - stats: Stats - languages: Array - contact_account: Account | null - max_toot_chars?: number - registrations?: boolean - configuration?: { - statuses: { - max_characters: number - max_media_attachments: number - characters_reserved_per_url: number - } - media_attachments: { - supported_mime_types: Array - image_size_limit: number - image_matrix_limit: number - video_size_limit: number - video_frame_limit: number - video_matrix_limit: number - } - polls: { - max_options: number - max_characters_per_option: number - min_expiration: number - max_expiration: number - } - } - } -} diff --git a/megalodon/src/pleroma/entities/list.ts b/megalodon/src/pleroma/entities/list.ts deleted file mode 100644 index a3d4362..0000000 --- a/megalodon/src/pleroma/entities/list.ts +++ /dev/null @@ -1,6 +0,0 @@ -namespace PleromaEntity { - export type List = { - id: string - title: string - } -} diff --git a/megalodon/src/pleroma/entities/marker.ts b/megalodon/src/pleroma/entities/marker.ts deleted file mode 100644 index 720d4a9..0000000 --- a/megalodon/src/pleroma/entities/marker.ts +++ /dev/null @@ -1,12 +0,0 @@ -namespace PleromaEntity { - export type Marker = { - notifications: { - last_read_id: string - version: number - updated_at: string - pleroma: { - unread_count: number - } - } - } -} diff --git a/megalodon/src/pleroma/entities/mention.ts b/megalodon/src/pleroma/entities/mention.ts deleted file mode 100644 index 0d68b4e..0000000 --- a/megalodon/src/pleroma/entities/mention.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace PleromaEntity { - export type Mention = { - id: string - username: string - url: string - acct: string - } -} diff --git a/megalodon/src/pleroma/entities/notification.ts b/megalodon/src/pleroma/entities/notification.ts deleted file mode 100644 index 7e59562..0000000 --- a/megalodon/src/pleroma/entities/notification.ts +++ /dev/null @@ -1,15 +0,0 @@ -/// -/// - -namespace PleromaEntity { - export type Notification = { - account: Account - created_at: string - id: string - status?: Status - emoji?: string - type: NotificationType - } - - export type NotificationType = string -} diff --git a/megalodon/src/pleroma/entities/poll.ts b/megalodon/src/pleroma/entities/poll.ts deleted file mode 100644 index 82e0182..0000000 --- a/megalodon/src/pleroma/entities/poll.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -namespace PleromaEntity { - export type Poll = { - id: string - expires_at: string | null - expired: boolean - multiple: boolean - votes_count: number - options: Array - voted: boolean - } -} diff --git a/megalodon/src/pleroma/entities/poll_option.ts b/megalodon/src/pleroma/entities/poll_option.ts deleted file mode 100644 index 69717ca..0000000 --- a/megalodon/src/pleroma/entities/poll_option.ts +++ /dev/null @@ -1,6 +0,0 @@ -namespace PleromaEntity { - export type PollOption = { - title: string - votes_count: number | null - } -} diff --git a/megalodon/src/pleroma/entities/preferences.ts b/megalodon/src/pleroma/entities/preferences.ts deleted file mode 100644 index 99f8d6b..0000000 --- a/megalodon/src/pleroma/entities/preferences.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace PleromaEntity { - export type Preferences = { - 'posting:default:visibility': 'public' | 'unlisted' | 'private' | 'direct' - 'posting:default:sensitive': boolean - 'posting:default:language': string | null - 'reading:expand:media': 'default' | 'show_all' | 'hide_all' - 'reading:expand:spoilers': boolean - } -} diff --git a/megalodon/src/pleroma/entities/push_subscription.ts b/megalodon/src/pleroma/entities/push_subscription.ts deleted file mode 100644 index b3e14e6..0000000 --- a/megalodon/src/pleroma/entities/push_subscription.ts +++ /dev/null @@ -1,16 +0,0 @@ -namespace PleromaEntity { - export type Alerts = { - follow: boolean - favourite: boolean - mention: boolean - reblog: boolean - poll: boolean - } - - export type PushSubscription = { - id: string - endpoint: string - server_key: string - alerts: Alerts - } -} diff --git a/megalodon/src/pleroma/entities/reaction.ts b/megalodon/src/pleroma/entities/reaction.ts deleted file mode 100644 index 662600f..0000000 --- a/megalodon/src/pleroma/entities/reaction.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -namespace PleromaEntity { - export type Reaction = { - count: number - me: boolean - name: string - accounts?: Array - } -} diff --git a/megalodon/src/pleroma/entities/relationship.ts b/megalodon/src/pleroma/entities/relationship.ts deleted file mode 100644 index d77154e..0000000 --- a/megalodon/src/pleroma/entities/relationship.ts +++ /dev/null @@ -1,16 +0,0 @@ -namespace PleromaEntity { - export type Relationship = { - id: string - following: boolean - followed_by: boolean - blocking: boolean - blocked_by: boolean - muting: boolean - muting_notifications: boolean - requested: boolean - domain_blocking: boolean - showing_reblogs: boolean - endorsed: boolean - subscribing: boolean - } -} diff --git a/megalodon/src/pleroma/entities/report.ts b/megalodon/src/pleroma/entities/report.ts deleted file mode 100644 index 2870110..0000000 --- a/megalodon/src/pleroma/entities/report.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace PleromaEntity { - export type Report = { - id: string - action_taken: string - comment: string - account_id: string - status_ids: Array - } -} diff --git a/megalodon/src/pleroma/entities/results.ts b/megalodon/src/pleroma/entities/results.ts deleted file mode 100644 index cd42e3b..0000000 --- a/megalodon/src/pleroma/entities/results.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// -/// -/// - -namespace PleromaEntity { - export type Results = { - accounts: Array - statuses: Array - hashtags: Array - } -} diff --git a/megalodon/src/pleroma/entities/scheduled_status.ts b/megalodon/src/pleroma/entities/scheduled_status.ts deleted file mode 100644 index ce9ca6f..0000000 --- a/megalodon/src/pleroma/entities/scheduled_status.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// -/// -namespace PleromaEntity { - export type ScheduledStatus = { - id: string - scheduled_at: string - params: StatusParams - media_attachments: Array - } -} diff --git a/megalodon/src/pleroma/entities/source.ts b/megalodon/src/pleroma/entities/source.ts deleted file mode 100644 index f2fa74a..0000000 --- a/megalodon/src/pleroma/entities/source.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// -namespace PleromaEntity { - export type Source = { - privacy: string | null - sensitive: boolean | null - language: string | null - note: string - fields: Array - } -} diff --git a/megalodon/src/pleroma/entities/stats.ts b/megalodon/src/pleroma/entities/stats.ts deleted file mode 100644 index ab3e778..0000000 --- a/megalodon/src/pleroma/entities/stats.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace PleromaEntity { - export type Stats = { - user_count: number - status_count: number - domain_count: number - } -} diff --git a/megalodon/src/pleroma/entities/status.ts b/megalodon/src/pleroma/entities/status.ts deleted file mode 100644 index dfaa744..0000000 --- a/megalodon/src/pleroma/entities/status.ts +++ /dev/null @@ -1,60 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// - -namespace PleromaEntity { - export type Status = { - id: string - uri: string - url: string - account: Account - in_reply_to_id: string | null - in_reply_to_account_id: string | null - reblog: Status | null - content: string - created_at: string - emojis: Emoji[] - replies_count: number - reblogs_count: number - favourites_count: number - reblogged: boolean | null - favourited: boolean | null - muted: boolean | null - sensitive: boolean - spoiler_text: string - visibility: 'public' | 'unlisted' | 'private' | 'direct' - media_attachments: Array - mentions: Array - tags: Array - card: Card | null - poll: Poll | null - application: Application | null - language: string | null - pinned: boolean | null - bookmarked?: boolean - // Reblogged status contains only local parameter. - pleroma: { - content?: { - 'text/plain': string - } - spoiler_text?: { - 'text/plain': string - } - conversation_id?: number - direct_conversation_id?: number | null - emoji_reactions?: Array - expires_at?: string - in_reply_to_account_acct?: string - local: boolean - parent_visible?: boolean - pinned_at?: string - thread_muted?: boolean - } - } -} diff --git a/megalodon/src/pleroma/entities/status_params.ts b/megalodon/src/pleroma/entities/status_params.ts deleted file mode 100644 index fb2877b..0000000 --- a/megalodon/src/pleroma/entities/status_params.ts +++ /dev/null @@ -1,12 +0,0 @@ -namespace PleromaEntity { - export type StatusParams = { - text: string - in_reply_to_id: string | null - media_ids: Array | null - sensitive: boolean | null - spoiler_text: string | null - visibility: 'public' | 'unlisted' | 'private' | 'direct' - scheduled_at: string | null - application_id: string - } -} diff --git a/megalodon/src/pleroma/entities/tag.ts b/megalodon/src/pleroma/entities/tag.ts deleted file mode 100644 index 4d7b0ff..0000000 --- a/megalodon/src/pleroma/entities/tag.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -namespace PleromaEntity { - export type Tag = { - name: string - url: string - history: Array | null - following?: boolean - } -} diff --git a/megalodon/src/pleroma/entities/token.ts b/megalodon/src/pleroma/entities/token.ts deleted file mode 100644 index 0ac565b..0000000 --- a/megalodon/src/pleroma/entities/token.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace PleromaEntity { - export type Token = { - access_token: string - token_type: string - scope: string - created_at: number - } -} diff --git a/megalodon/src/pleroma/entities/urls.ts b/megalodon/src/pleroma/entities/urls.ts deleted file mode 100644 index 7ad6faf..0000000 --- a/megalodon/src/pleroma/entities/urls.ts +++ /dev/null @@ -1,5 +0,0 @@ -namespace PleromaEntity { - export type URLs = { - streaming_api: string - } -} diff --git a/megalodon/src/pleroma/entity.ts b/megalodon/src/pleroma/entity.ts deleted file mode 100644 index f2d27da..0000000 --- a/megalodon/src/pleroma/entity.ts +++ /dev/null @@ -1,38 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// > -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// - -export default PleromaEntity diff --git a/megalodon/src/pleroma/notification.ts b/megalodon/src/pleroma/notification.ts deleted file mode 100644 index e1069c7..0000000 --- a/megalodon/src/pleroma/notification.ts +++ /dev/null @@ -1,13 +0,0 @@ -import PleromaEntity from './entity' - -namespace PleromaNotificationType { - export const Mention: PleromaEntity.NotificationType = 'mention' - export const Reblog: PleromaEntity.NotificationType = 'reblog' - export const Favourite: PleromaEntity.NotificationType = 'favourite' - export const Follow: PleromaEntity.NotificationType = 'follow' - export const Poll: PleromaEntity.NotificationType = 'poll' - export const PleromaEmojiReaction: PleromaEntity.NotificationType = 'pleroma:emoji_reaction' - export const FollowRequest: PleromaEntity.NotificationType = 'follow_request' -} - -export default PleromaNotificationType diff --git a/megalodon/src/pleroma/web_socket.ts b/megalodon/src/pleroma/web_socket.ts deleted file mode 100644 index 17ea29d..0000000 --- a/megalodon/src/pleroma/web_socket.ts +++ /dev/null @@ -1,343 +0,0 @@ -import WS from 'ws' -import dayjs, { Dayjs } from 'dayjs' -import { EventEmitter } from 'events' - -import proxyAgent, { ProxyConfig } from '../proxy_config' -import { WebSocketInterface } from '../megalodon' -import PleromaAPI from './api_client' - -/** - * WebSocket - * Pleroma is not support streaming. It is support websocket instead of streaming. - * So this class connect to Phoenix websocket for Pleroma. - */ -export default class WebSocket extends EventEmitter implements WebSocketInterface { - public url: string - public stream: string - public params: string | null - public parser: Parser - public headers: { [key: string]: string } - public proxyConfig: ProxyConfig | false = false - private _accessToken: string - private _reconnectInterval: number - private _reconnectMaxAttempts: number - private _reconnectCurrentAttempts: number - private _connectionClosed: boolean - private _client: WS | null - private _pongReceivedTimestamp: Dayjs - private _heartbeatInterval: number = 60000 - private _pongWaiting: boolean = false - - /** - * @param url Full url of websocket: e.g. https://pleroma.io/api/v1/streaming - * @param stream Stream name, please refer: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/mastodon_api/mastodon_socket.ex#L19-28 - * @param accessToken The access token. - * @param userAgent The specified User Agent. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor( - url: string, - stream: string, - params: string | undefined, - accessToken: string, - userAgent: string, - proxyConfig: ProxyConfig | false = false - ) { - super() - this.url = url - this.stream = stream - if (params === undefined) { - this.params = null - } else { - this.params = params - } - this.parser = new Parser() - this.headers = { - 'User-Agent': userAgent - } - this.proxyConfig = proxyConfig - this._accessToken = accessToken - this._reconnectInterval = 10000 - this._reconnectMaxAttempts = Infinity - this._reconnectCurrentAttempts = 0 - this._connectionClosed = false - this._client = null - this._pongReceivedTimestamp = dayjs() - } - - /** - * Start websocket connection. - */ - public start() { - this._connectionClosed = false - this._resetRetryParams() - this._startWebSocketConnection() - } - - /** - * Reset connection and start new websocket connection. - */ - private _startWebSocketConnection() { - this._resetConnection() - this._setupParser() - this._client = this._connect(this.url, this.stream, this.params, this._accessToken, this.headers, this.proxyConfig) - this._bindSocket(this._client) - } - - /** - * Stop current connection. - */ - public stop() { - this._connectionClosed = true - this._resetConnection() - this._resetRetryParams() - } - - /** - * Clean up current connection, and listeners. - */ - private _resetConnection() { - if (this._client) { - this._client.close(1000) - this._client.removeAllListeners() - this._client = null - } - - if (this.parser) { - this.parser.removeAllListeners() - } - } - - /** - * Resets the parameters used in reconnect. - */ - private _resetRetryParams() { - this._reconnectCurrentAttempts = 0 - } - - /** - * Reconnects to the same endpoint. - */ - private _reconnect() { - setTimeout(() => { - // Skip reconnect when client is connecting. - // https://github.com/websockets/ws/blob/7.2.1/lib/websocket.js#L365 - if (this._client && this._client.readyState === WS.CONNECTING) { - return - } - - if (this._reconnectCurrentAttempts < this._reconnectMaxAttempts) { - this._reconnectCurrentAttempts++ - this._clearBinding() - if (this._client) { - // In reconnect, we want to close the connection immediately, - // because recoonect is necessary when some problems occur. - this._client.terminate() - } - // Call connect methods - console.log('Reconnecting') - this._client = this._connect(this.url, this.stream, this.params, this._accessToken, this.headers, this.proxyConfig) - this._bindSocket(this._client) - } - }, this._reconnectInterval) - } - - /** - * @param url Base url of streaming endpoint. - * @param stream The specified stream name. - * @param accessToken Access token. - * @param headers The specified headers. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - * @return A WebSocket instance. - */ - private _connect( - url: string, - stream: string, - params: string | null, - accessToken: string, - headers: { [key: string]: string }, - proxyConfig: ProxyConfig | false - ): WS { - const parameter: Array = [`stream=${stream}`] - - if (params) { - parameter.push(params) - } - - if (accessToken !== null) { - parameter.push(`access_token=${accessToken}`) - } - const requestURL: string = `${url}/?${parameter.join('&')}` - let options: WS.ClientOptions = { - headers: headers - } - if (proxyConfig) { - options = Object.assign(options, { - agent: proxyAgent(proxyConfig) - }) - } - - const cli: WS = new WS(requestURL, options) - return cli - } - - /** - * Clear binding event for web socket client. - */ - private _clearBinding() { - if (this._client) { - this._client.removeAllListeners('close') - this._client.removeAllListeners('pong') - this._client.removeAllListeners('open') - this._client.removeAllListeners('message') - this._client.removeAllListeners('error') - } - } - - /** - * Bind event for web socket client. - * @param client A WebSocket instance. - */ - private _bindSocket(client: WS) { - client.on('close', (code: number, _reason: Buffer) => { - // Refer the code: https://tools.ietf.org/html/rfc6455#section-7.4 - if (code === 1000) { - this.emit('close', {}) - } else { - console.log(`Closed connection with ${code}`) - // If already called close method, it does not retry. - if (!this._connectionClosed) { - this._reconnect() - } - } - }) - client.on('pong', () => { - this._pongWaiting = false - this.emit('pong', {}) - this._pongReceivedTimestamp = dayjs() - // It is required to anonymous function since get this scope in checkAlive. - setTimeout(() => this._checkAlive(this._pongReceivedTimestamp), this._heartbeatInterval) - }) - client.on('open', () => { - this.emit('connect', {}) - // Call first ping event. - setTimeout(() => { - client.ping('') - }, 10000) - }) - client.on('message', (data: WS.Data, isBinary: boolean) => { - this.parser.parse(data, isBinary) - }) - client.on('error', (err: Error) => { - this.emit('error', err) - }) - } - - /** - * Set up parser when receive message. - */ - private _setupParser() { - this.parser.on('update', (status: PleromaAPI.Entity.Status) => { - this.emit('update', PleromaAPI.Converter.status(status)) - }) - this.parser.on('notification', (notification: PleromaAPI.Entity.Notification) => { - this.emit('notification', PleromaAPI.Converter.notification(notification)) - }) - this.parser.on('delete', (id: string) => { - this.emit('delete', id) - }) - this.parser.on('conversation', (conversation: PleromaAPI.Entity.Conversation) => { - this.emit('conversation', PleromaAPI.Converter.conversation(conversation)) - }) - this.parser.on('status_update', (status: PleromaAPI.Entity.Status) => { - this.emit('status_update', PleromaAPI.Converter.status(status)) - }) - this.parser.on('error', (err: Error) => { - this.emit('parser-error', err) - }) - this.parser.on('heartbeat', _ => { - this.emit('heartbeat', 'heartbeat') - }) - } - - /** - * Call ping and wait to pong. - */ - private _checkAlive(timestamp: Dayjs) { - const now: Dayjs = dayjs() - // Block multiple calling, if multiple pong event occur. - // It the duration is less than interval, through ping. - if (now.diff(timestamp) > this._heartbeatInterval - 1000 && !this._connectionClosed) { - // Skip ping when client is connecting. - // https://github.com/websockets/ws/blob/7.2.1/lib/websocket.js#L289 - if (this._client && this._client.readyState !== WS.CONNECTING) { - this._pongWaiting = true - this._client.ping('') - setTimeout(() => { - if (this._pongWaiting) { - this._pongWaiting = false - this._reconnect() - } - }, 10000) - } - } - } -} - -/** - * Parser - * This class provides parser for websocket message. - */ -export class Parser extends EventEmitter { - /** - * @param message Message body of websocket. - */ - public parse(data: WS.Data, isBinary: boolean) { - const message = isBinary ? data : data.toString() - if (typeof message !== 'string') { - this.emit('heartbeat', {}) - return - } - - if (message === '') { - this.emit('heartbeat', {}) - return - } - - let event = '' - let payload = '' - let mes = {} - try { - const obj = JSON.parse(message) - event = obj.event - payload = obj.payload - mes = JSON.parse(payload) - } catch (err) { - // delete event does not have json object - if (event !== 'delete') { - this.emit('error', new Error(`Error parsing websocket reply: ${message}, error message: ${err}`)) - return - } - } - - switch (event) { - case 'update': - this.emit('update', mes as PleromaAPI.Entity.Status) - break - case 'notification': - this.emit('notification', mes as PleromaAPI.Entity.Notification) - break - case 'conversation': - this.emit('conversation', mes as PleromaAPI.Entity.Conversation) - break - case 'delete': - this.emit('delete', payload) - break - case 'status.update': - this.emit('status_update', mes as PleromaAPI.Entity.Status) - break - default: - this.emit('error', new Error(`Unknown event has received: ${message}`)) - } - } -} diff --git a/megalodon/test/integration/cancel.spec.ts b/megalodon/test/integration/cancel.spec.ts deleted file mode 100644 index efc9d49..0000000 --- a/megalodon/test/integration/cancel.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import MastodonAPI from '@/mastodon/api_client' -import { Worker } from 'jest-worker' - -jest.mock('axios', () => { - const mockAxios = jest.requireActual('axios') - mockAxios.get = (_path: string) => { - return new Promise(resolve => { - setTimeout(() => { - console.log('hoge') - resolve({ - data: 'hoge', - status: 200, - statusText: '200OK', - headers: [], - config: {} - }) - }, 5000) - }) - } - return mockAxios -}) - -const worker = async (client: MastodonAPI.Client) => { - const w: any = new Worker(require.resolve('./cancelWorker.ts')) - await w.cancel(client) -} - -// Could not use jest-worker under typescript. -// I'm waiting for resolve this issue. -// https://github.com/facebook/jest/issues/8872 -describe.skip('cancel', () => { - const client = new MastodonAPI.Client('testToken', 'https://pleroma.io/api/v1') - it('should be raised', async () => { - const getPromise = client.get<{}>('/timelines/home') - worker(client) - await expect(getPromise).rejects.toThrow() - }) -}) diff --git a/megalodon/test/integration/cancelWorker.ts b/megalodon/test/integration/cancelWorker.ts deleted file mode 100644 index 17a0722..0000000 --- a/megalodon/test/integration/cancelWorker.ts +++ /dev/null @@ -1,5 +0,0 @@ -import MastodonAPI from '@/mastodon/api_client' - -export function cancel(client: MastodonAPI.Client) { - return client.cancel() -} diff --git a/megalodon/test/integration/mastodon.spec.ts b/megalodon/test/integration/mastodon.spec.ts deleted file mode 100644 index 1c359fb..0000000 --- a/megalodon/test/integration/mastodon.spec.ts +++ /dev/null @@ -1,182 +0,0 @@ -import MastodonEntity from '@/mastodon/entity' -import MastodonNotificationType from '@/mastodon/notification' -import Mastodon from '@/mastodon' -import MegalodonNotificationType from '@/notification' -import axios, { AxiosResponse } from 'axios' - -jest.mock('axios') - -const account: MastodonEntity.Account = { - id: '1', - username: 'h3poteto', - acct: 'h3poteto@pleroma.io', - display_name: 'h3poteto', - locked: false, - created_at: '2019-03-26T21:30:32', - followers_count: 10, - following_count: 10, - statuses_count: 100, - note: 'engineer', - url: 'https://pleroma.io', - avatar: '', - avatar_static: '', - header: '', - header_static: '', - emojis: [], - moved: null, - fields: [], - bot: false -} - -const status: MastodonEntity.Status = { - id: '1', - uri: 'http://example.com', - url: 'http://example.com', - account: account, - in_reply_to_id: null, - in_reply_to_account_id: null, - reblog: null, - content: 'hoge', - created_at: '2019-03-26T21:40:32', - emojis: [], - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - reblogged: null, - favourited: null, - muted: null, - sensitive: false, - spoiler_text: '', - visibility: 'public', - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: { - name: 'Web' - } as MastodonEntity.Application, - language: null, - pinned: null, - bookmarked: false -} - -const follow: MastodonEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '1', - type: MastodonNotificationType.Follow -} - -const favourite: MastodonEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '2', - status: status, - type: MastodonNotificationType.Favourite -} - -const mention: MastodonEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '3', - status: status, - type: MastodonNotificationType.Mention -} - -const reblog: MastodonEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '4', - status: status, - type: MastodonNotificationType.Reblog -} - -const poll: MastodonEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '5', - type: MastodonNotificationType.Poll -} - -const followRequest: MastodonEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '6', - type: MastodonNotificationType.FollowRequest -} - -const toot: MastodonEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '7', - status: status, - type: MastodonNotificationType.Status -} - -;(axios.CancelToken.source as any).mockImplementation(() => { - return { - token: { - throwIfRequested: () => {}, - promise: { - then: () => {}, - catch: () => {} - } - } - } -}) - -describe('getNotifications', () => { - const client = new Mastodon('http://localhost', 'sample token') - const cases: Array<{ event: MastodonEntity.Notification; expected: Entity.NotificationType; title: string }> = [ - { - event: follow, - expected: MegalodonNotificationType.Follow, - title: 'follow' - }, - { - event: favourite, - expected: MegalodonNotificationType.Favourite, - title: 'favourite' - }, - { - event: mention, - expected: MegalodonNotificationType.Mention, - title: 'mention' - }, - { - event: reblog, - expected: MegalodonNotificationType.Reblog, - title: 'reblog' - }, - { - event: poll, - expected: MegalodonNotificationType.PollExpired, - title: 'poll' - }, - { - event: followRequest, - expected: MegalodonNotificationType.FollowRequest, - title: 'followRequest' - }, - { - event: toot, - expected: MegalodonNotificationType.Status, - title: 'status' - } - ] - cases.forEach(c => { - it(`should be ${c.title} event`, async () => { - const mockResponse: AxiosResponse> = { - data: [c.event], - status: 200, - statusText: '200OK', - headers: {}, - config: {} - } - ;(axios.get as any).mockResolvedValue(mockResponse) - const res = await client.getNotifications() - expect(res.data[0].type).toEqual(c.expected) - }) - }) -}) diff --git a/megalodon/test/integration/mastodon/api_client.spec.ts b/megalodon/test/integration/mastodon/api_client.spec.ts deleted file mode 100644 index 3ea72f3..0000000 --- a/megalodon/test/integration/mastodon/api_client.spec.ts +++ /dev/null @@ -1,161 +0,0 @@ -import MastodonAPI from '@/mastodon/api_client' -import Entity from '@/entity' -import Response from '@/response' -import axios, { AxiosResponse } from 'axios' - -jest.mock('axios') - -const account: Entity.Account = { - id: '1', - username: 'h3poteto', - acct: 'h3poteto@pleroma.io', - display_name: 'h3poteto', - locked: false, - created_at: '2019-03-26T21:30:32', - followers_count: 10, - following_count: 10, - statuses_count: 100, - note: 'engineer', - url: 'https://pleroma.io', - avatar: '', - avatar_static: '', - header: '', - header_static: '', - emojis: [], - moved: null, - fields: [], - bot: false -} - -const status: Entity.Status = { - id: '1', - uri: 'http://example.com', - url: 'http://example.com', - account: account, - in_reply_to_id: null, - in_reply_to_account_id: null, - reblog: null, - content: 'hoge', - plain_content: null, - created_at: '2019-03-26T21:40:32', - emojis: [], - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - reblogged: null, - favourited: null, - muted: null, - sensitive: false, - spoiler_text: '', - visibility: 'public', - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: { - name: 'Web' - } as Entity.Application, - language: null, - pinned: null, - emoji_reactions: [], - bookmarked: false, - quote: null -} -;(axios.CancelToken.source as any).mockImplementation(() => { - return { - token: { - throwIfRequested: () => {}, - promise: { - then: () => {}, - catch: () => {} - } - } - } -}) - -describe('get', () => { - const client = new MastodonAPI.Client('testToken', 'https://pleroma.io/api/v1') - const mockResponse: AxiosResponse> = { - data: [status], - status: 200, - statusText: '200OK', - headers: {}, - config: {} - } - it('should be responsed', async () => { - ;(axios.get as any).mockResolvedValue(mockResponse) - const response: Response> = await client.get>('/timelines/home') - expect(response.data).toEqual([status]) - }) -}) - -describe('put', () => { - const client = new MastodonAPI.Client('testToken', 'https://pleroma.io/api/v1') - const mockResponse: AxiosResponse = { - data: account, - status: 200, - statusText: '200OK', - headers: {}, - config: {} - } - it('should be responsed', async () => { - ;(axios.put as any).mockResolvedValue(mockResponse) - const response: Response = await client.put('/accounts/update_credentials', { - display_name: 'hoge' - }) - expect(response.data).toEqual(account) - }) -}) - -describe('patch', () => { - const client = new MastodonAPI.Client('testToken', 'https://pleroma.io/api/v1') - const mockResponse: AxiosResponse = { - data: account, - status: 200, - statusText: '200OK', - headers: {}, - config: {} - } - it('should be responsed', async () => { - ;(axios.patch as any).mockResolvedValue(mockResponse) - const response: Response = await client.patch('/accounts/update_credentials', { - display_name: 'hoge' - }) - expect(response.data).toEqual(account) - }) -}) - -describe('post', () => { - const client = new MastodonAPI.Client('testToken', 'https://pleroma.io/api/v1') - const mockResponse: AxiosResponse = { - data: status, - status: 200, - statusText: '200OK', - headers: {}, - config: {} - } - it('should be responsed', async () => { - ;(axios.post as any).mockResolvedValue(mockResponse) - const response: Response = await client.post('/statuses', { - status: 'hoge' - }) - expect(response.data).toEqual(status) - }) -}) - -describe('del', () => { - const client = new MastodonAPI.Client('testToken', 'https://pleroma.io/api/v1') - const mockResponse: AxiosResponse<{}> = { - data: {}, - status: 200, - statusText: '200OK', - headers: {}, - config: {} - } - it('should be responsed', async () => { - ;(axios.delete as any).mockResolvedValue(mockResponse) - const response: Response<{}> = await client.del<{}>('/statuses/12asdf34') - expect(response.data).toEqual({}) - }) -}) diff --git a/megalodon/test/integration/pleroma.spec.ts b/megalodon/test/integration/pleroma.spec.ts deleted file mode 100644 index 5a8e66a..0000000 --- a/megalodon/test/integration/pleroma.spec.ts +++ /dev/null @@ -1,187 +0,0 @@ -import PleromaEntity from '@/pleroma/entity' -import Pleroma from '@/pleroma' -import MegalodonNotificationType from '@/notification' -import PleromaNotificationType from '@/pleroma/notification' -import axios, { AxiosResponse } from 'axios' - -jest.mock('axios') - -const account: PleromaEntity.Account = { - id: '1', - username: 'h3poteto', - acct: 'h3poteto@pleroma.io', - display_name: 'h3poteto', - locked: false, - created_at: '2019-03-26T21:30:32', - followers_count: 10, - following_count: 10, - statuses_count: 100, - note: 'engineer', - url: 'https://pleroma.io', - avatar: '', - avatar_static: '', - header: '', - header_static: '', - emojis: [], - moved: null, - fields: [], - bot: false -} - -const status: PleromaEntity.Status = { - id: '1', - uri: 'http://example.com', - url: 'http://example.com', - account: account, - in_reply_to_id: null, - in_reply_to_account_id: null, - reblog: null, - content: 'hoge', - created_at: '2019-03-26T21:40:32', - emojis: [], - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - reblogged: null, - favourited: null, - muted: null, - sensitive: false, - spoiler_text: '', - visibility: 'public', - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: { - name: 'Web' - } as MastodonEntity.Application, - language: null, - pinned: null, - bookmarked: false, - pleroma: { - local: false - } -} - -const follow: PleromaEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '1', - type: PleromaNotificationType.Follow -} - -const favourite: PleromaEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '2', - type: PleromaNotificationType.Favourite, - status: status -} - -const mention: PleromaEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '3', - type: PleromaNotificationType.Mention, - status: status -} - -const reblog: PleromaEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '4', - type: PleromaNotificationType.Reblog, - status: status -} - -const poll: PleromaEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '5', - type: PleromaNotificationType.Poll, - status: status -} - -const emojiReaction: PleromaEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '6', - type: PleromaNotificationType.PleromaEmojiReaction, - status: status, - emoji: '♥' -} - -const followRequest: PleromaEntity.Notification = { - account: account, - created_at: '2021-01-31T23:33:26', - id: '7', - type: PleromaNotificationType.FollowRequest -} - -;(axios.CancelToken.source as any).mockImplementation(() => { - return { - token: { - throwIfRequested: () => {}, - promise: { - then: () => {}, - catch: () => {} - } - } - } -}) - -describe('getNotifications', () => { - const client = new Pleroma('http://localhost', 'sample token') - const cases: Array<{ event: PleromaEntity.Notification; expected: Entity.NotificationType; title: string }> = [ - { - event: follow, - expected: MegalodonNotificationType.Follow, - title: 'follow' - }, - { - event: favourite, - expected: MegalodonNotificationType.Favourite, - title: 'favourite' - }, - { - event: mention, - expected: MegalodonNotificationType.Mention, - title: 'mention' - }, - { - event: reblog, - expected: MegalodonNotificationType.Reblog, - title: 'reblog' - }, - { - event: poll, - expected: MegalodonNotificationType.PollExpired, - title: 'poll' - }, - { - event: emojiReaction, - expected: MegalodonNotificationType.EmojiReaction, - title: 'emojiReaction' - }, - { - event: followRequest, - expected: MegalodonNotificationType.FollowRequest, - title: 'followRequest' - } - ] - cases.forEach(c => { - it(`should be ${c.title} event`, async () => { - const mockResponse: AxiosResponse> = { - data: [c.event], - status: 200, - statusText: '200OK', - headers: {}, - config: {} - } - ;(axios.get as any).mockResolvedValue(mockResponse) - const res = await client.getNotifications() - expect(res.data[0].type).toEqual(c.expected) - }) - }) -}) diff --git a/megalodon/test/unit/mastodon.spec.ts b/megalodon/test/unit/mastodon.spec.ts deleted file mode 100644 index 311f60d..0000000 --- a/megalodon/test/unit/mastodon.spec.ts +++ /dev/null @@ -1,6 +0,0 @@ -describe('test', () => { - it('should be true', () => { - const res = true - expect(res).toEqual(true) - }) -}) diff --git a/megalodon/test/unit/mastodon/api_client.spec.ts b/megalodon/test/unit/mastodon/api_client.spec.ts deleted file mode 100644 index 1e3c6b5..0000000 --- a/megalodon/test/unit/mastodon/api_client.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import MastodonAPI from '@/mastodon/api_client' -import MegalodonEntity from '@/entity' -import MastodonEntity from '@/mastodon/entity' -import MegalodonNotificationType from '@/notification' -import MastodonNotificationType from '@/mastodon/notification' - -describe('api_client', () => { - describe('notification', () => { - describe('encode', () => { - it('megalodon notification type should be encoded to mastodon notification type', () => { - const cases: Array<{ src: MegalodonEntity.NotificationType; dist: MastodonEntity.NotificationType }> = [ - { - src: MegalodonNotificationType.Follow, - dist: MastodonNotificationType.Follow - }, - { - src: MegalodonNotificationType.Favourite, - dist: MastodonNotificationType.Favourite - }, - { - src: MegalodonNotificationType.Reblog, - dist: MastodonNotificationType.Reblog - }, - { - src: MegalodonNotificationType.Mention, - dist: MastodonNotificationType.Mention - }, - { - src: MegalodonNotificationType.PollExpired, - dist: MastodonNotificationType.Poll - }, - { - src: MegalodonNotificationType.FollowRequest, - dist: MastodonNotificationType.FollowRequest - }, - { - src: MegalodonNotificationType.Status, - dist: MastodonNotificationType.Status - } - ] - cases.forEach(c => { - expect(MastodonAPI.Converter.encodeNotificationType(c.src)).toEqual(c.dist) - }) - }) - }) - describe('decode', () => { - it('mastodon notification type should be decoded to megalodon notification type', () => { - const cases: Array<{ src: MastodonEntity.NotificationType; dist: MegalodonEntity.NotificationType }> = [ - { - src: MastodonNotificationType.Follow, - dist: MegalodonNotificationType.Follow - }, - { - src: MastodonNotificationType.Favourite, - dist: MegalodonNotificationType.Favourite - }, - { - src: MastodonNotificationType.Mention, - dist: MegalodonNotificationType.Mention - }, - { - src: MastodonNotificationType.Reblog, - dist: MegalodonNotificationType.Reblog - }, - { - src: MastodonNotificationType.Poll, - dist: MegalodonNotificationType.PollExpired - }, - { - src: MastodonNotificationType.FollowRequest, - dist: MegalodonNotificationType.FollowRequest - } - ] - cases.forEach(c => { - expect(MastodonAPI.Converter.decodeNotificationType(c.src)).toEqual(c.dist) - }) - }) - }) - }) -}) diff --git a/megalodon/test/unit/pleroma/api_client.spec.ts b/megalodon/test/unit/pleroma/api_client.spec.ts deleted file mode 100644 index 55f52d1..0000000 --- a/megalodon/test/unit/pleroma/api_client.spec.ts +++ /dev/null @@ -1,200 +0,0 @@ -import PleromaAPI from '@/pleroma/api_client' -import MegalodonEntity from '@/entity' -import PleromaEntity from '@/pleroma/entity' -import MegalodonNotificationType from '@/notification' -import PleromaNotificationType from '@/pleroma/notification' - -const account: PleromaEntity.Account = { - id: '1', - username: 'h3poteto', - acct: 'h3poteto@pleroma.io', - display_name: 'h3poteto', - locked: false, - created_at: '2019-03-26T21:30:32', - followers_count: 10, - following_count: 10, - statuses_count: 100, - note: 'engineer', - url: 'https://pleroma.io', - avatar: '', - avatar_static: '', - header: '', - header_static: '', - emojis: [], - moved: null, - fields: [], - bot: false -} - -describe('api_client', () => { - describe('notification', () => { - describe('encode', () => { - it('megalodon notification type should be encoded to pleroma notification type', () => { - const cases: Array<{ src: MegalodonEntity.NotificationType; dist: PleromaEntity.NotificationType }> = [ - { - src: MegalodonNotificationType.Follow, - dist: PleromaNotificationType.Follow - }, - { - src: MegalodonNotificationType.Favourite, - dist: PleromaNotificationType.Favourite - }, - { - src: MegalodonNotificationType.Reblog, - dist: PleromaNotificationType.Reblog - }, - { - src: MegalodonNotificationType.Mention, - dist: PleromaNotificationType.Mention - }, - { - src: MegalodonNotificationType.PollExpired, - dist: PleromaNotificationType.Poll - }, - { - src: MegalodonNotificationType.EmojiReaction, - dist: PleromaNotificationType.PleromaEmojiReaction - }, - { - src: MegalodonNotificationType.FollowRequest, - dist: PleromaNotificationType.FollowRequest - } - ] - cases.forEach(c => { - expect(PleromaAPI.Converter.encodeNotificationType(c.src)).toEqual(c.dist) - }) - }) - }) - describe('decode', () => { - it('pleroma notification type should be decoded to megalodon notification type', () => { - const cases: Array<{ src: PleromaEntity.NotificationType; dist: MegalodonEntity.NotificationType }> = [ - { - src: PleromaNotificationType.Follow, - dist: MegalodonNotificationType.Follow - }, - { - src: PleromaNotificationType.Favourite, - dist: MegalodonNotificationType.Favourite - }, - { - src: PleromaNotificationType.Mention, - dist: MegalodonNotificationType.Mention - }, - { - src: PleromaNotificationType.Reblog, - dist: MegalodonNotificationType.Reblog - }, - { - src: PleromaNotificationType.Poll, - dist: MegalodonNotificationType.PollExpired - }, - { - src: PleromaNotificationType.PleromaEmojiReaction, - dist: MegalodonNotificationType.EmojiReaction - }, - { - src: PleromaNotificationType.FollowRequest, - dist: MegalodonNotificationType.FollowRequest - } - ] - cases.forEach(c => { - expect(PleromaAPI.Converter.decodeNotificationType(c.src)).toEqual(c.dist) - }) - }) - }) - }) - - describe('status', () => { - describe('plain content is included', () => { - it('plain content in pleroma entity should be exported in plain_content column', () => { - const plainContent = 'hoge\nfuga\nfuga' - const content = '

hoge
fuga
fuga

' - const pleromaStatus: PleromaEntity.Status = { - id: '1', - uri: 'https://pleroma.io/notice/1', - url: 'https://pleroma.io/notice/1', - account: account, - in_reply_to_id: null, - in_reply_to_account_id: null, - reblog: null, - content: content, - created_at: '2019-03-26T21:40:32', - emojis: [], - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - reblogged: null, - favourited: null, - muted: null, - sensitive: false, - spoiler_text: '', - visibility: 'public', - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: { - name: 'Web' - } as MastodonEntity.Application, - language: null, - pinned: null, - bookmarked: false, - pleroma: { - content: { - 'text/plain': plainContent - }, - local: false - } - } - const megalodonStatus = PleromaAPI.Converter.status(pleromaStatus) - expect(megalodonStatus.plain_content).toEqual(plainContent) - expect(megalodonStatus.content).toEqual(content) - }) - }) - - describe('plain content is not included', () => { - it('plain_content should be null', () => { - const content = '

hoge
fuga
fuga

' - const pleromaStatus: PleromaEntity.Status = { - id: '1', - uri: 'https://pleroma.io/notice/1', - url: 'https://pleroma.io/notice/1', - account: account, - in_reply_to_id: null, - in_reply_to_account_id: null, - reblog: null, - content: content, - created_at: '2019-03-26T21:40:32', - emojis: [], - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - reblogged: null, - favourited: null, - muted: null, - sensitive: false, - spoiler_text: '', - visibility: 'public', - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: { - name: 'Web' - } as MastodonEntity.Application, - language: null, - pinned: null, - bookmarked: false, - pleroma: { - local: false - } - } - const megalodonStatus = PleromaAPI.Converter.status(pleromaStatus) - expect(megalodonStatus.plain_content).toBeNull() - expect(megalodonStatus.content).toEqual(content) - }) - }) - }) -}) diff --git a/megalodon/test/unit/webo_socket.spec.ts b/megalodon/test/unit/webo_socket.spec.ts deleted file mode 100644 index 5015a9e..0000000 --- a/megalodon/test/unit/webo_socket.spec.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { Parser } from '@/mastodon/web_socket' -import Entity from '@/entity' - -const account: Entity.Account = { - id: '1', - username: 'h3poteto', - acct: 'h3poteto@pleroma.io', - display_name: 'h3poteto', - locked: false, - created_at: '2019-03-26T21:30:32', - followers_count: 10, - following_count: 10, - statuses_count: 100, - note: 'engineer', - url: 'https://pleroma.io', - avatar: '', - avatar_static: '', - header: '', - header_static: '', - emojis: [], - moved: null, - fields: [], - bot: false -} -const status: Entity.Status = { - id: '1', - uri: 'http://example.com', - url: 'http://example.com', - account: account, - in_reply_to_id: null, - in_reply_to_account_id: null, - reblog: null, - content: 'hoge', - plain_content: 'hoge', - created_at: '2019-03-26T21:40:32', - emojis: [], - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - reblogged: null, - favourited: null, - muted: null, - sensitive: false, - spoiler_text: '', - visibility: 'public', - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: { - name: 'Web' - } as Entity.Application, - language: null, - pinned: null, - emoji_reactions: [], - bookmarked: false, - quote: null -} - -const notification: Entity.Notification = { - id: '1', - account: account, - status: status, - type: 'favourite', - created_at: '2019-04-01T17:01:32' -} - -const conversation: Entity.Conversation = { - id: '1', - accounts: [account], - last_status: status, - unread: true -} - -describe('Parser', () => { - let parser: Parser - - beforeEach(() => { - parser = new Parser() - }) - - describe('parse', () => { - describe('message is heartbeat', () => { - describe('message is an object', () => { - const message = Buffer.alloc(0) - - it('should be called', () => { - const spy = jest.fn() - parser.once('heartbeat', spy) - parser.parse(message, true) - expect(spy).toHaveBeenCalledWith({}) - }) - }) - describe('message is empty string', () => { - const message: string = '' - - it('should be called', () => { - const spy = jest.fn() - parser.once('heartbeat', spy) - parser.parse(Buffer.from(message), false) - expect(spy).toHaveBeenCalledWith({}) - }) - }) - }) - - describe('message is not json', () => { - describe('event is delete', () => { - const message = JSON.stringify({ - event: 'delete', - payload: '12asdf34' - }) - - it('should be called', () => { - const spy = jest.fn() - parser.once('delete', spy) - parser.parse(Buffer.from(message), false) - expect(spy).toHaveBeenCalledWith('12asdf34') - }) - }) - describe('event is not delete', () => { - const message = JSON.stringify({ - event: 'event', - payload: '12asdf34' - }) - - it('should be called', () => { - const error = jest.fn() - const deleted = jest.fn() - parser.once('error', error) - parser.once('delete', deleted) - parser.parse(Buffer.from(message), false) - expect(error).toHaveBeenCalled() - expect(deleted).not.toHaveBeenCalled() - }) - }) - }) - - describe('message is json', () => { - describe('event is update', () => { - const message = JSON.stringify({ - event: 'update', - payload: JSON.stringify(status) - }) - it('should be called', () => { - const spy = jest.fn() - parser.once('update', spy) - parser.parse(Buffer.from(message), false) - expect(spy).toHaveBeenCalledWith(status) - }) - }) - - describe('event is notification', () => { - const message = JSON.stringify({ - event: 'notification', - payload: JSON.stringify(notification) - }) - it('should be called', () => { - const spy = jest.fn() - parser.once('notification', spy) - parser.parse(Buffer.from(message), false) - expect(spy).toHaveBeenCalledWith(notification) - }) - }) - - describe('event is conversation', () => { - const message = JSON.stringify({ - event: 'conversation', - payload: JSON.stringify(conversation) - }) - it('should be called', () => { - const spy = jest.fn() - parser.once('conversation', spy) - parser.parse(Buffer.from(message), false) - expect(spy).toHaveBeenCalledWith(conversation) - }) - }) - }) - }) -})