UNPKG

@cutls/megalodon

Version:

Mastodon, Pleroma, Misskey API client for node.js and browser

1,469 lines 58.5 kB
import FormData from 'form-data'; import MisskeyAPI from './misskey/api_client.js'; import { DEFAULT_UA } from './default.js'; import MisskeyOAuth from './misskey_oauth.js'; import { NotImplementedError, ArgumentError, UnexpectedError } from './megalodon.js'; export default class Misskey { client; baseUrl; constructor(baseUrl, accessToken = null, userAgent = DEFAULT_UA) { let token = ''; if (accessToken) { token = accessToken; } let agent = DEFAULT_UA; if (userAgent) { agent = userAgent; } this.client = new MisskeyAPI.Client(baseUrl, token, agent); this.baseUrl = baseUrl; } baseUrlToHost(baseUrl) { return baseUrl.replace('https://', ''); } cancel() { return this.client.cancel(); } async registerApp(client_name, options = { scopes: MisskeyAPI.DEFAULT_SCOPE, redirect_uris: this.baseUrl }) { return this.createApp(client_name, options).then(async (appData) => { return this.generateAuthUrlAndToken(appData.client_secret).then(session => { appData.url = session.url; appData.session_token = session.token; return appData; }); }); } async createApp(client_name, options = { scopes: MisskeyAPI.DEFAULT_SCOPE, redirect_uris: this.baseUrl }) { const redirect_uris = options.redirect_uris || this.baseUrl; const scopes = options.scopes || MisskeyAPI.DEFAULT_SCOPE; const params = { name: client_name, description: '', permission: scopes, callbackUrl: redirect_uris }; return this.client.post('/api/app/create', params).then((res) => { const appData = { id: res.data.id, name: res.data.name, website: null, redirect_uri: res.data.callbackUrl, client_id: '', client_secret: res.data.secret }; return MisskeyOAuth.AppData.from(appData); }); } async generateAuthUrlAndToken(clientSecret) { return this.client .post('/api/auth/session/generate', { appSecret: clientSecret }) .then((res) => res.data); } async verifyAppCredentials() { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async fetchAccessToken(_client_id, client_secret, session_token, _redirect_uri) { return this.client .post('/api/auth/session/userkey', { appSecret: client_secret, token: session_token }) .then((res) => { const token = new MisskeyOAuth.TokenData(res.data.accessToken, 'misskey', '', 0, null, null); return token; }); } async refreshToken(_client_id, _client_secret, _refresh_token) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async revokeToken(_client_id, _client_secret, _token) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async registerAccount(_username, _email, _password, _agreement, _locale, _reason) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async verifyAccountCredentials() { return this.client.post('/api/i').then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.userDetail(res.data, this.baseUrlToHost(this.baseUrl)) }); }); } async updateCredentials(options) { let params = {}; if (options) { if (options.bot !== undefined) { params = Object.assign(params, { isBot: options.bot }); } if (options.display_name) { params = Object.assign(params, { name: options.display_name }); } if (options.note) { params = Object.assign(params, { description: options.note }); } if (options.locked !== undefined) { params = Object.assign(params, { isLocked: options.locked }); } if (options.source) { if (options.source.language) { params = Object.assign(params, { lang: options.source.language }); } if (options.source.sensitive) { params = Object.assign(params, { alwaysMarkNsfw: options.source.sensitive }); } } } return this.client.post('/api/i', params).then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.userDetail(res.data, this.baseUrlToHost(this.baseUrl)) }); }); } async getAccount(id) { return this.client .post('/api/users/show', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.userDetail(res.data, this.baseUrlToHost(this.baseUrl)) }); }); } async getAccountStatuses(id, options) { if (options && options.pinned) { return this.client .post('/api/users/show', { userId: id }) .then(res => { if (res.data.pinnedNotes) { return { ...res, data: res.data.pinnedNotes.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }; } return { ...res, data: [] }; }); } let params = { userId: id }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.exclude_replies) { params = Object.assign(params, { includeReplies: false }); } if (options.exclude_reblogs) { params = Object.assign(params, { includeMyRenotes: false }); } if (options.only_media) { params = Object.assign(params, { withFiles: options.only_media }); } } return this.client.post('/api/users/notes', params).then(res => { const statuses = res.data.map(note => MisskeyAPI.Converter.note(note, this.baseUrlToHost(this.baseUrl))); return Object.assign(res, { data: statuses }); }); } async getAccountFavourites(_id, _options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async subscribeAccount(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async unsubscribeAccount(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getAccountFollowers(id, options) { let params = { userId: id }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } } return this.client.post('/api/users/followers', params).then(res => { return Object.assign(res, { data: res.data.map(f => MisskeyAPI.Converter.follower(f, this.baseUrlToHost(this.baseUrl))) }); }); } async getAccountFollowing(id, options) { let params = { userId: id }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } } return this.client.post('/api/users/following', params).then(res => { return Object.assign(res, { data: res.data.map(f => MisskeyAPI.Converter.following(f, this.baseUrlToHost(this.baseUrl))) }); }); } async getAccountLists(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getIdentityProof(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async followAccount(id, _options) { await this.client.post('/api/following/create', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async unfollowAccount(id) { await this.client.post('/api/following/delete', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async blockAccount(id) { await this.client.post('/api/blocking/create', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async unblockAccount(id) { await this.client.post('/api/blocking/delete', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async muteAccount(id, _notifications) { await this.client.post('/api/mute/create', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async unmuteAccount(id) { await this.client.post('/api/mute/delete', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async pinAccount(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async unpinAccount(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async setAccountNote(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support this method'); reject(err); }); } async getRelationship(id) { return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data[0]) }); }); } async getRelationships(ids) { return Promise.all(ids.map(id => this.getRelationship(id))).then(results => ({ ...results[0], data: results.map(r => r.data) })); } async searchAccount(q, options) { let params = { query: q, detail: true }; if (options) { params = Object.assign(params, { localOnly: !options.resolve }); if (options.limit) { params = Object.assign(params, { limit: options.limit }); } } return this.client.post('/api/users/search', params).then(res => { return Object.assign(res, { data: res.data.map(u => MisskeyAPI.Converter.userDetail(u, this.baseUrlToHost(this.baseUrl))) }); }); } async lookupAccount(acct) { const params = { query: acct, detail: true }; return this.client.post('/api/users/search', params).then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.user(res.data[0], this.baseUrlToHost(this.baseUrl)) }); }); } async getBookmarks(_options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getFavourites(options) { let params = {}; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client.post('/api/i/favorites', params).then(res => { return Object.assign(res, { data: res.data.map(fav => MisskeyAPI.Converter.note(fav.note, this.baseUrlToHost(this.baseUrl))) }); }); } async getMutes(options) { let params = {}; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client.post('/api/mute/list', params).then(res => { return Object.assign(res, { data: res.data.map(mute => MisskeyAPI.Converter.userDetail(mute.mutee, this.baseUrlToHost(this.baseUrl))) }); }); } async getBlocks(options) { let params = {}; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client.post('/api/blocking/list', params).then(res => { return Object.assign(res, { data: res.data.map(blocking => MisskeyAPI.Converter.userDetail(blocking.blockee, this.baseUrlToHost(this.baseUrl))) }); }); } async getDomainBlocks(_options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async blockDomain(_domain) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async unblockDomain(_domain) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getFilters() { return this.client.post('/api/i', { scope: ['client', 'base'] }).then(res => { return Object.assign(res, { data: res.data.mutedWords.map(f => ({ id: f.join('_'), phrase: f.join(' '), context: ['home', 'notifications', 'public', 'thread'], expires_at: null, irreversible: false, whole_word: false })) }); }); } async getFilter(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async createFilter(_phrase, _context, _options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async updateFilter(_id, _phrase, _context, _options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async deleteFilter(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async report(account_id, options) { return this.client .post('/api/users/report-abuse', { userId: account_id, comment: options?.comment || '' }) .then(res => { return Object.assign(res, { data: { id: '', action_taken: false, comment: options?.comment || '', account_id: account_id, status_ids: [], category: null, forwarded: null, action_taken_at: null, rule_ids: null } }); }); } async getFollowRequests(_limit) { return this.client.post('/api/following/requests/list').then(res => { return Object.assign(res, { data: res.data.map(r => MisskeyAPI.Converter.user(r.follower, this.baseUrlToHost(this.baseUrl))) }); }); } async acceptFollowRequest(id) { await this.client.post('/api/following/requests/accept', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async rejectFollowRequest(id) { await this.client.post('/api/following/requests/reject', { userId: id }); return this.client .post('/api/users/relation', { userId: id }) .then(res => { return Object.assign(res, { data: MisskeyAPI.Converter.relation(res.data) }); }); } async getEndorsements(_options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getFeaturedTags() { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async createFeaturedTag(_name) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async deleteFeaturedTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getSuggestedTags() { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getPreferences() { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getSuggestions(limit) { let params = {}; if (limit) { params = Object.assign(params, { limit: limit }); } return this.client .post('/api/users/recommendation', params) .then(res => ({ ...res, data: res.data.map(u => MisskeyAPI.Converter.userDetail(u, this.baseUrlToHost(this.baseUrl))) })); } async getTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async followTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async unfollowTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async postStatus(status, options) { let params = { text: status }; if (options) { if (options.media_ids) { params = Object.assign(params, { fileIds: options.media_ids }); } if (options.poll) { let pollParam = { choices: options.poll.options, expiresAt: null, expiredAfter: options.poll.expires_in }; if (options.poll.multiple !== undefined) { pollParam = Object.assign(pollParam, { multiple: options.poll.multiple }); } params = Object.assign(params, { poll: pollParam }); } if (options.in_reply_to_id) { params = Object.assign(params, { replyId: options.in_reply_to_id }); } if (options.sensitive) { params = Object.assign(params, { cw: '' }); } if (options.spoiler_text) { params = Object.assign(params, { cw: options.spoiler_text }); } if (options.visibility) { params = Object.assign(params, { visibility: MisskeyAPI.Converter.encodeVisibility(options.visibility) }); } if (options.quoted_status_id) { params = Object.assign(params, { renoteId: options.quoted_status_id }); } } return this.client .post('/api/notes/create', params) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data.createdNote, this.baseUrlToHost(this.baseUrl)) })); } async getStatus(id) { return this.client .post('/api/notes/show', { noteId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) })); } async getStatusSource(id) { return this.client .post('/api/notes/show', { noteId: id }) .then(res => ({ ...res, data: { id, text: res.data.text || '', spoiler_text: res.data.cw || '' } })); } async editStatus(_id, _options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async revokeQuote(_yourId, _quotingId) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async deleteStatus(id) { return this.client.post('/api/notes/delete', { noteId: id }); } async getStatusContext(id, options) { let params = { noteId: id }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } } return this.client.post('/api/notes/children', params).then(res => { const context = { ancestors: [], descendants: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }; return { ...res, data: context }; }); } async getStatusRebloggedBy(id) { return this.client .post('/api/notes/renotes', { noteId: id }) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.user(n.user, this.baseUrlToHost(this.baseUrl))) })); } async getStatusFavouritedBy(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async favouriteStatus(id) { await this.client.post('/api/notes/favorites/create', { noteId: id }); return this.client .post('/api/notes/show', { noteId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) })); } async unfavouriteStatus(id) { await this.client.post('/api/notes/favorites/delete', { noteId: id }); return this.client .post('/api/notes/show', { noteId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) })); } async reblogStatus(id) { return this.client .post('/api/notes/create', { renoteId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data.createdNote, this.baseUrlToHost(this.baseUrl)) })); } async unreblogStatus(id) { await this.client.post('/api/notes/unrenote', { noteId: id }); return this.client .post('/api/notes/show', { noteId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) })); } async bookmarkStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async unbookmarkStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async muteStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async unmuteStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async pinStatus(id) { await this.client.post('/api/i/pin', { noteId: id }); return this.client .post('/api/notes/show', { noteId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) })); } async unpinStatus(id) { await this.client.post('/api/i/unpin', { noteId: id }); return this.client .post('/api/notes/show', { noteId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) })); } async uploadMedia(file, _options) { const formData = new FormData(); formData.append('file', file); let headers = {}; if (typeof formData.getHeaders === 'function') { headers = formData.getHeaders(); } return this.client .post('/api/drive/files/create', formData, headers) .then(res => ({ ...res, data: MisskeyAPI.Converter.file(res.data) })); } async getMedia(id) { const res = await this.client.post('/api/drive/files/show', { fileId: id }); return { ...res, data: MisskeyAPI.Converter.file(res.data) }; } async updateMedia(id, options) { let params = { fileId: id }; if (options) { if (options.is_sensitive !== undefined) { params = Object.assign(params, { isSensitive: options.is_sensitive }); } } return this.client .post('/api/drive/files/update', params) .then(res => ({ ...res, data: MisskeyAPI.Converter.file(res.data) })); } async getPoll(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async votePoll(_id, choices, status_id) { if (!status_id) { return new Promise((_, reject) => { const err = new ArgumentError('status_id is required'); reject(err); }); } const params = { noteId: status_id, choice: choices[0] }; await this.client.post('/api/notes/polls/vote', params); const res = await this.client .post('/api/notes/show', { noteId: status_id }) .then(res => { const note = MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)); return { ...res, data: note.poll }; }); if (!res.data) { return new Promise((_, reject) => { const err = new UnexpectedError('poll does not exist'); reject(err); }); } return { ...res, data: res.data }; } async getScheduledStatuses(_options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getScheduledStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async scheduleStatus(_id, _scheduled_at) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async cancelScheduledStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getPublicTimeline(options) { let params = {}; if (options) { if (options.only_media !== undefined) { params = Object.assign(params, { withFiles: options.only_media }); } if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client .post('/api/notes/global-timeline', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) })); } async getLocalTimeline(options) { let params = {}; if (options) { if (options.only_media !== undefined) { params = Object.assign(params, { withFiles: options.only_media }); } if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client .post('/api/notes/local-timeline', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) })); } async getTagTimeline(hashtag, options) { let params = { tag: hashtag }; if (options) { if (options.only_media !== undefined) { params = Object.assign(params, { withFiles: options.only_media }); } if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client .post('/api/notes/search-by-tag', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) })); } async getIntegratedTimeline(options) { let params = { withFiles: false }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } const home = await this.client.post('/api/notes/timeline', params); const local = await this.client.post('/api/notes/local-timeline', params); const merged = [...home.data, ...local.data.map(s => ({ ...s, _integrated_isLocal: true }))].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); const uniqueData = Array.from(new Map(merged.map(item => [item.id, item])).values()); return { ...home, data: uniqueData.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }; } async getHomeTimeline(options) { let params = { withFiles: false }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client .post('/api/notes/timeline', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) })); } async getListTimeline(list_id, options, isAntenna) { let params = { listId: isAntenna ? undefined : list_id, antennaId: isAntenna ? list_id : undefined, withFiles: false }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } if (isAntenna) { return this.client .post('/api/antennas/notes', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) })); } return this.client .post('/api/notes/user-list-timeline', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) })); } async getConversationTimeline(options) { let params = { visibility: 'specified' }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } } return this.client .post('/api/notes/mentions', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.noteToConversation(n, this.baseUrlToHost(this.baseUrl))) })); } async deleteConversation(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async readConversation(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getLists(includeAntenna) { const lists = this.client .post('/api/users/lists/list') .then(res => ({ ...res, data: res.data.map(l => MisskeyAPI.Converter.list(l)) })); if (!includeAntenna) return lists; const antennas = this.client .post('/api/antennas/list') .then(res => ({ ...res, data: res.data.map(a => MisskeyAPI.Converter.antennaToList(a)) })); const [listsRes, antennasRes] = await Promise.all([lists, antennas]); return { ...listsRes, data: listsRes.data.concat(antennasRes.data) }; } async getList(id) { return this.client .post('/api/users/lists/show', { listId: id }) .then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) })); } async createList(title) { return this.client .post('/api/users/lists/create', { name: title }) .then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) })); } async updateList(id, title) { return this.client .post('/api/users/lists/update', { listId: id, name: title }) .then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) })); } async deleteList(id) { return this.client.post('/api/users/lists/delete', { listId: id }); } async getAccountsInList(id, _options) { const res = await this.client.post('/api/users/lists/show', { listId: id }); const promise = res.data.userIds.map(userId => this.getAccount(userId)); const accounts = await Promise.all(promise); return { ...res, data: accounts.map(r => r.data) }; } async addAccountsToList(id, account_ids) { return this.client.post('/api/users/lists/push', { listId: id, userId: account_ids[0] }); } async deleteAccountsFromList(id, account_ids) { return this.client.post('/api/users/lists/pull', { listId: id, userId: account_ids[0] }); } async getMarkers(_timeline) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async saveMarkers(_options) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getNotifications(options) { let params = {}; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.since_id) { params = Object.assign(params, { sinceId: options.since_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } if (options.exclude_type) { params = Object.assign(params, { excludeType: options.exclude_type.map(e => MisskeyAPI.Converter.encodeNotificationType(e)) }); } } return this.client .post('/api/i/notifications', params) .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.notification(n, this.baseUrlToHost(this.baseUrl))) })); } async getNotification(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async dismissNotifications() { return this.client.post('/api/notifications/mark-all-as-read'); } async dismissNotification(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async readNotifications(_options) { return new Promise((_, reject) => { const err = new NotImplementedError('mastodon does not support'); reject(err); }); } async subscribePushNotification(_subscription, _data) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async getPushSubscription() { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async updatePushSubscription(_data) { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async deletePushSubscription() { return new Promise((_, reject) => { const err = new NotImplementedError('misskey does not support'); reject(err); }); } async search(q, options) { switch (options?.type) { case 'accounts': { let params = { query: q }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.offset) { params = Object.assign(params, { offset: options.offset }); } params = Object.assign(params, { localOnly: !options.resolve }); } return this.client.post('/api/users/search', params).then(res => ({ ...res, data: { accounts: res.data.map(u => MisskeyAPI.Converter.userDetail(u, this.baseUrlToHost(this.baseUrl))), statuses: [], hashtags: [] } })); } case 'statuses': { let params = { query: q }; if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }); } if (options.offset) { params = Object.assign(params, { offset: options.offset }); } if (options.max_id) { params = Object.assign(params, { untilId: options.max_id }); } if (options.min_id) { params = Object.assign(params, { sinceId: options.min_id }); } if (options.account_id) { params = Object.assign(params, { userId: options.account_id }); } } return this.client.post('/api/notes/search', params).then(res => ({ ...res, data: { accounts: [], statuses: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))), hashtags: [] } })); } case 'hashtags': { let params =