import axios from 'axios'; import Cookies from 'universal-cookie'; const apiBaseUrl = 'https://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 }); client.interceptors.request.use(config => { if (config.url.startsWith('/')) { // only local URLs let cookies = new Cookies(); config.params = Object.assign(config.params || {}, { hash: cookies.get('hash') }); } return config; }); /** * fetch my info * * @param {string} username * @param {string} password * @returns {Promise} me object */ export function me(username = '', password = '') { let cookies = new Cookies(); return new Promise((resolve, reject) => { client.get('/api/me', { headers: username ? { 'Authorization': 'Basic ' + window.btoa(unescape(encodeURIComponent(username + ':' + password))) } : {} }).then(response => { let visitor = response.data; cookies.set('hash', visitor.hash, { path: '/' }); resolve(visitor); }).catch(reason => { cookies.remove('hash', { path: '/' }); reject(reason); }); }); } /** * @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 };