import axios from 'axios' const apiBaseUrl = 'https://beta.juick.com' /** * @typedef {object} Token * @property {string} type * @property {string} token */ /** * @typedef { object } TagStats * @property { string } tag */ /** * @typedef {object} User * @property {string=} uname * @property {number} uid * @property {number=} unreadCount * @property {string=} avatar * @property {User[]=} read * @property {User[]=} readers * @property {number=} statsMyBL * @property {string=} uri */ /** * @typedef {object} SecureUserProperties * @property {string=} hash * @property {Token[]=} tokens * @property {string=} telegramName * @property {string=} twitterName * @property {string[]=} jids * @property {string[]=} emails * @property {string=} activeEmail * @property {{connected: boolean, crosspostEnabled: boolean}=} facebookStatus */ /** * @typedef {User & SecureUserProperties} SecureUser */ /** * @typedef {object} ChatProperties * @property {number=} unreadCount * @property {string=} lastMessageText */ /** * @typedef {User & ChatProperties} Chat */ /** * @typedef {object} Message * @property {string} body * @property {number=} mid * @property {number=} rid * @property {boolean=} service * @property {User} user * @property {User=} to * @property {string=} replyQuote * @property {string[]=} tags * @property {number=} likes * @property {number=} replies * @property {string=} photo * @property {string=} attach * @property {string=} timestamp * @property {boolean=} ReadOnly * @property {number=} replyto */ const client = axios.create({ baseURL: apiBaseUrl, withCredentials: true }) /** * fetch my info * @returns {Promise} me object */ export function me() { return client.get('/api/me') } /** * @param {string} username */ export function info(username) { return client.get(`/api/info/${username}`) } /** * */ export function getChats() { return client.get('/api/groups_pms') } /** * @param {string} userName */ export function getChat(userName) { return client.get('/api/pm', { params: { 'uname': userName } }) } /** * @param {string} userName * @param {string} body */ export function pm(userName, body) { let form = new FormData() form.set('uname', userName) form.set('body', body) return client.post('/api/pm', form) } /** * @param {string} path * @param {{ mid: any; }} params */ export function getMessages(path, params) { return client.get(path, { params: params }) } /** * @param {string} body * @param {string} attach */ export function post(body, attach) { let form = new FormData() form.append('attach', attach) form.append('body', body) return client.post('/api/post', form) } /** * @param {number} mid * @param {number} rid * @param {string} body * @param {string} attach */ export function comment(mid, rid, body, attach) { let form = new FormData() form.append('mid', mid.toString()) form.append('rid', rid.toString()) form.append('body', body) form.append('attach', attach) return client.post('/api/comment', form) } /** * Edit message * @param {number} mid * @param {number} rid * @param {string?} body */ export function update(mid, rid, body) { let form = new FormData() form.append('mid', mid) form.append('rid', rid) form.append('body', body) return client.post('/api/update', form) } /** * Update user avatar * @param {string} newAvatar */ export function updateAvatar(newAvatar) { let form = new FormData() form.append('avatar', newAvatar) return client.post('/api/me/upload', form) } /** * @param {string} network */ function socialLink(network) { return `${apiBaseUrl}/api/_${network}login?state=${window.location.protocol}//${window.location.host}${window.location.pathname}` } /** * */ export function facebookLink() { return socialLink('fb') } /** * */ export function vkLink() { return socialLink('vk') } /** * */ export function appleLink() { return socialLink('apple') } /** * @param {Message} msg * @param {SecureUser} visitor */ export function markReadTracker(msg, visitor) { return `${apiBaseUrl}/api/thread/mark_read/${msg.mid}-${msg.rid || 0}.gif?hash=${visitor.hash}` } let profileCache = {} /** * Fetch user profile * @param {string} profileUrl User profile URL */ export function fetchUserUri(profileUrl) { return new Promise((resolve, reject) => { if (profileCache[profileUrl]) { resolve(profileCache[profileUrl]) } else { client.get(profileUrl, { headers: { 'Accept': 'application/ld+json' } }).then(response => { profileCache[profileUrl] = response.data resolve(response.data) }).catch(reject) } }) } /** * * @returns { Promise } tags */ export const trends = async () => { try { const response = await client.get('/api/tags') return response.data } catch (e) { console.error(e) return [] } } /** * Fetch Tweet content * @param {string} url Tweet URL * @returns {Promise} HTML content */ const embeddedTweet = async (url = '') => { const response = await axios.get('https://publish.twitter.com/oembed', { params: { 'dnt': true, 'omit_script': true, 'url': url } }) return response.data } /** * Checks if HTTP error code is redirection code * @param {number} code HTTP error code * @returns {boolean} is HTTP request redirected or not */ function isHttpRedirected(code = 200) { return [301, 302].includes(code) } /** * Checks if HTTP error code is successful code * @param {number} code HTTP error code * @returns {boolean} is HTTP request successful or not */ function isHttpSuccessful(code = 200) { return code >= 200 && code < 300 } /** * Resolves shortened url to actual one * @param {string} url URL to resolve * @returns {Promise} full URL */ function expandShortenedLink(url = '') { return new Promise((resolve, reject) => { axios.head(url, { maxRedirects: 0 }).then(response => { if (isHttpSuccessful(response.status)) { // URL is not redirected resolve(url) return } if (isHttpRedirected(response.status)) { resolve(/** @type { string } */ (response.headers['Location'])) return } // Error case reject('Invalid response') }).catch(error => { reject(error) }) }) } export { embeddedTweet, expandShortenedLink }