|
|
@ -1,6 +1,7 @@
|
|
|
|
/* eslint sort-keys: "error" */
|
|
|
|
/* eslint sort-keys: "error" */
|
|
|
|
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
|
|
|
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
|
|
|
import { createSelector } from 'reselect';
|
|
|
|
import { createSelector } from 'reselect';
|
|
|
|
|
|
|
|
import semverCoerce from 'semver/functions/coerce';
|
|
|
|
import gte from 'semver/functions/gte';
|
|
|
|
import gte from 'semver/functions/gte';
|
|
|
|
import lt from 'semver/functions/lt';
|
|
|
|
import lt from 'semver/functions/lt';
|
|
|
|
import semverParse from 'semver/functions/parse';
|
|
|
|
import semverParse from 'semver/functions/parse';
|
|
|
@ -16,16 +17,16 @@ const overrides = custom('features');
|
|
|
|
const any = (arr: Array<any>): boolean => arr.some(Boolean);
|
|
|
|
const any = (arr: Array<any>): boolean => arr.some(Boolean);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Mastodon, the software upon which this is all based.
|
|
|
|
* Friendica, decentralized social platform implementing multiple federation protocols.
|
|
|
|
* @see {@link https://joinmastodon.org/}
|
|
|
|
* @see {@link https://friendi.ca/}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const MASTODON = 'Mastodon';
|
|
|
|
export const FRIENDICA = 'Friendica';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Pleroma, a feature-rich alternative written in Elixir.
|
|
|
|
* Mastodon, the software upon which this is all based.
|
|
|
|
* @see {@link https://pleroma.social/}
|
|
|
|
* @see {@link https://joinmastodon.org/}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const PLEROMA = 'Pleroma';
|
|
|
|
export const MASTODON = 'Mastodon';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Mitra, a Rust backend with deep Ethereum integrations.
|
|
|
|
* Mitra, a Rust backend with deep Ethereum integrations.
|
|
|
@ -40,23 +41,27 @@ export const MITRA = 'Mitra';
|
|
|
|
export const PIXELFED = 'Pixelfed';
|
|
|
|
export const PIXELFED = 'Pixelfed';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Truth Social, the Mastodon fork powering truthsocial.com
|
|
|
|
* Pleroma, a feature-rich alternative written in Elixir.
|
|
|
|
* @see {@link https://help.truthsocial.com/open-source}
|
|
|
|
* @see {@link https://pleroma.social/}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const TRUTHSOCIAL = 'TruthSocial';
|
|
|
|
export const PLEROMA = 'Pleroma';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Rebased, the recommended backend for Soapbox.
|
|
|
|
* Takahē, backend with support for serving multiple domains.
|
|
|
|
* @see {@link https://gitlab.com/soapbox-pub/rebased}
|
|
|
|
* @see {@link https://jointakahe.org/}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
// NOTE: Rebased is named 'soapbox' for legacy reasons.
|
|
|
|
export const TAKAHE = 'Takahe';
|
|
|
|
export const REBASED = 'soapbox';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* glitch-soc, fork of Mastodon with a number of experimental features.
|
|
|
|
* Truth Social, the Mastodon fork powering truthsocial.com
|
|
|
|
* @see {@link https://glitch-soc.github.io/docs/}
|
|
|
|
* @see {@link https://help.truthsocial.com/open-source}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const GLITCH = 'glitch';
|
|
|
|
export const TRUTHSOCIAL = 'TruthSocial';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Wildebeest, backend running on top of Cloudflare Pages.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export const WILDEBEEST = 'Wildebeest';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Akkoma, a Pleroma fork.
|
|
|
|
* Akkoma, a Pleroma fork.
|
|
|
@ -65,15 +70,17 @@ export const GLITCH = 'glitch';
|
|
|
|
export const AKKOMA = 'akkoma';
|
|
|
|
export const AKKOMA = 'akkoma';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Takahē, backend with support for serving multiple domains.
|
|
|
|
* glitch-soc, fork of Mastodon with a number of experimental features.
|
|
|
|
* @see {@link https://jointakahe.org/}
|
|
|
|
* @see {@link https://glitch-soc.github.io/docs/}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const TAKAHE = 'Takahe';
|
|
|
|
export const GLITCH = 'glitch';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Wildebeest, backend running on top of Cloudflare Pages.
|
|
|
|
* Rebased, the recommended backend for Soapbox.
|
|
|
|
|
|
|
|
* @see {@link https://gitlab.com/soapbox-pub/rebased}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const WILDEBEEST = 'Wildebeest';
|
|
|
|
// NOTE: Rebased is named 'soapbox' for legacy reasons.
|
|
|
|
|
|
|
|
export const REBASED = 'soapbox';
|
|
|
|
|
|
|
|
|
|
|
|
/** Parse features for the given instance */
|
|
|
|
/** Parse features for the given instance */
|
|
|
|
const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
const getInstanceFeatures = (instance: Instance) => {
|
|
|
@ -207,6 +214,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see GET /api/v1/bookmarks
|
|
|
|
* @see GET /api/v1/bookmarks
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
bookmarks: any([
|
|
|
|
bookmarks: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '3.1.0'),
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '3.1.0'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
v.software === PIXELFED,
|
|
|
|
v.software === PIXELFED,
|
|
|
@ -301,6 +309,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see {@link https://docs.joinmastodon.org/methods/timelines/conversations/}
|
|
|
|
* @see {@link https://docs.joinmastodon.org/methods/timelines/conversations/}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
conversations: any([
|
|
|
|
conversations: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '2.6.0'),
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '2.6.0'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
v.software === PIXELFED,
|
|
|
|
v.software === PIXELFED,
|
|
|
@ -312,6 +321,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see GET /api/v1/timelines/direct
|
|
|
|
* @see GET /api/v1/timelines/direct
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
directTimeline: any([
|
|
|
|
directTimeline: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON && lt(v.compatVersion, '3.0.0'),
|
|
|
|
v.software === MASTODON && lt(v.compatVersion, '3.0.0'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
]),
|
|
|
|
]),
|
|
|
@ -321,6 +331,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see PATCH /api/v1/accounts/update_credentials
|
|
|
|
* @see PATCH /api/v1/accounts/update_credentials
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
editProfile: any([
|
|
|
|
editProfile: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON,
|
|
|
|
v.software === MASTODON,
|
|
|
|
v.software === MITRA,
|
|
|
|
v.software === MITRA,
|
|
|
|
v.software === PIXELFED,
|
|
|
|
v.software === PIXELFED,
|
|
|
@ -479,6 +490,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see GET /api/v1/timelines/list/:list_id
|
|
|
|
* @see GET /api/v1/timelines/list/:list_id
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
lists: any([
|
|
|
|
lists: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '2.1.0'),
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '2.1.0'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
v.software === PLEROMA && gte(v.version, '0.9.9'),
|
|
|
|
]),
|
|
|
|
]),
|
|
|
@ -592,6 +604,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see {@link https://docs.joinmastodon.org/methods/instance/directory/}
|
|
|
|
* @see {@link https://docs.joinmastodon.org/methods/instance/directory/}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
profileDirectory: any([
|
|
|
|
profileDirectory: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '3.0.0'),
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '3.0.0'),
|
|
|
|
features.includes('profile_directory'),
|
|
|
|
features.includes('profile_directory'),
|
|
|
|
]),
|
|
|
|
]),
|
|
|
@ -611,6 +624,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see GET /api/v1/timelines/public
|
|
|
|
* @see GET /api/v1/timelines/public
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
publicTimeline: any([
|
|
|
|
publicTimeline: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON,
|
|
|
|
v.software === MASTODON,
|
|
|
|
v.software === PLEROMA,
|
|
|
|
v.software === PLEROMA,
|
|
|
|
v.software === TAKAHE,
|
|
|
|
v.software === TAKAHE,
|
|
|
@ -736,6 +750,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|
|
|
* @see GET /api/v2/suggestions
|
|
|
|
* @see GET /api/v2/suggestions
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
suggestionsV2: any([
|
|
|
|
suggestionsV2: any([
|
|
|
|
|
|
|
|
v.software === FRIENDICA,
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '3.4.0'),
|
|
|
|
v.software === MASTODON && gte(v.compatVersion, '3.4.0'),
|
|
|
|
v.software === TRUTHSOCIAL,
|
|
|
|
v.software === TRUTHSOCIAL,
|
|
|
|
features.includes('v2_suggestions'),
|
|
|
|
features.includes('v2_suggestions'),
|
|
|
@ -816,8 +831,9 @@ export const parseVersion = (version: string): Backend => {
|
|
|
|
const regex = /^([\w+.]*)(?: \(compatible; ([\w]*) (.*)\))?$/;
|
|
|
|
const regex = /^([\w+.]*)(?: \(compatible; ([\w]*) (.*)\))?$/;
|
|
|
|
const match = regex.exec(version);
|
|
|
|
const match = regex.exec(version);
|
|
|
|
|
|
|
|
|
|
|
|
const semver = match ? semverParse(match[3] || match[1]) : null;
|
|
|
|
const semverString = match && (match[3] || match[1]);
|
|
|
|
const compat = match ? semverParse(match[1]) : null;
|
|
|
|
const semver = match ? semverParse(semverString) || semverCoerce(semverString) : null;
|
|
|
|
|
|
|
|
const compat = match ? semverParse(match[1]) || semverCoerce(match[1]) : null;
|
|
|
|
|
|
|
|
|
|
|
|
if (match && semver && compat) {
|
|
|
|
if (match && semver && compat) {
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|