From ab2e6b2ee385bd96709da154713d3c9f070c6a4f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 23 Apr 2022 15:40:54 -0500 Subject: [PATCH 1/2] Features: extensive documentation --- app/soapbox/components/sidebar-navigation.tsx | 6 +- app/soapbox/components/sidebar_menu.tsx | 22 +- app/soapbox/utils/features.ts | 322 +++++++++++++++++- 3 files changed, 322 insertions(+), 28 deletions(-) diff --git a/app/soapbox/components/sidebar-navigation.tsx b/app/soapbox/components/sidebar-navigation.tsx index eede8c871..bb8f47e4d 100644 --- a/app/soapbox/components/sidebar-navigation.tsx +++ b/app/soapbox/components/sidebar-navigation.tsx @@ -81,12 +81,12 @@ const SidebarNavigation = () => { }); } - if (features.localTimeline || features.publicTimeline) { + if (features.publicTimeline) { menu.push(null); } } - if (features.localTimeline) { + if (features.publicTimeline) { menu.push({ to: '/timeline/local', icon: features.federating ? require('@tabler/icons/icons/users.svg') : require('@tabler/icons/icons/world.svg'), @@ -94,7 +94,7 @@ const SidebarNavigation = () => { }); } - if (features.localTimeline && features.federating) { + if (features.publicTimeline && features.federating) { menu.push({ to: '/timeline/fediverse', icon: require('icons/fediverse.svg'), diff --git a/app/soapbox/components/sidebar_menu.tsx b/app/soapbox/components/sidebar_menu.tsx index e7cec5d95..2de745577 100644 --- a/app/soapbox/components/sidebar_menu.tsx +++ b/app/soapbox/components/sidebar_menu.tsx @@ -192,27 +192,25 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { onClick={onClose} /> - {(features.localTimeline || features.publicTimeline) && ( + {features.publicTimeline && <>
- )} - {features.localTimeline && ( } onClick={onClose} /> - )} - {(features.publicTimeline && features.federating) && ( - } - onClick={onClose} - /> - )} + {features.federating && ( + } + onClick={onClose} + /> + )} + }
diff --git a/app/soapbox/utils/features.ts b/app/soapbox/utils/features.ts index 27982f15d..49e9f7a2e 100644 --- a/app/soapbox/utils/features.ts +++ b/app/soapbox/utils/features.ts @@ -1,4 +1,3 @@ -// Detect backend features to conditionally render elements import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; import { createSelector } from 'reselect'; import gte from 'semver/functions/gte'; @@ -8,142 +7,432 @@ import { custom } from 'soapbox/custom'; import type { Instance } from 'soapbox/types/entities'; -// Import custom overrides, if exists +/** Import custom overrides, if exists */ const overrides = custom('features'); -// Truthy array convenience function +/** Truthy array convenience function */ const any = (arr: Array): boolean => arr.some(Boolean); -// For uglification -export const MASTODON = 'Mastodon'; -export const PLEROMA = 'Pleroma'; -export const MITRA = 'Mitra'; -export const TRUTHSOCIAL = 'TruthSocial'; -export const PIXELFED = 'Pixelfed'; +/** + * Mastodon, the software upon which this is all based. + * @see {@link https://joinmastodon.org/} + */ +export const MASTODON = 'Mastodon'; +/** + * Pleroma, a feature-rich alternative written in Elixir. + * @see {@link https://pleroma.social/} + */ +export const PLEROMA = 'Pleroma'; + +/** + * Mitra, a Rust backend with deep Ethereum integrations. + * @see {@link https://codeberg.org/silverpill/mitra} + */ +export const MITRA = 'Mitra'; + +/** + * Pixelfed, a federated image sharing platform. + * @see {@link https://pixelfed.org/} + */ +export const PIXELFED = 'Pixelfed'; + +/** + * Truth Social, the Mastodon fork powering truthsocial.com + * @see {@link https://help.truthsocial.com/open-source} + */ +export const TRUTHSOCIAL = 'TruthSocial'; + +/** Parse features for the given instance */ const getInstanceFeatures = (instance: Instance) => { const v = parseVersion(instance.version); const features = instance.pleroma.getIn(['metadata', 'features'], ImmutableList()) as ImmutableList; const federation = instance.pleroma.getIn(['metadata', 'federation'], ImmutableMap()) as ImmutableMap; return { + /** + * Can upload media attachments to statuses. + * @see POST /api/v1/media + * @see POST /api/v1/statuses + */ media: true, + + /** + * Can set privacy scopes on statuses. + * @see POST /api/v1/statuses + */ privacyScopes: v.software !== TRUTHSOCIAL, + + /** + * Can set content warnings on statuses. + * @see POST /api/v1/statuses + */ spoilers: v.software !== TRUTHSOCIAL, + + /** + * Can edit and manage timeline filters (aka "muted words"). + * @see {@link https://docs.joinmastodon.org/methods/accounts/filters/} + */ filters: v.software !== TRUTHSOCIAL, + + /** + * Can add polls to statuses. + * @see POST /api/v1/statuses + */ polls: any([ v.software === MASTODON && gte(v.version, '2.8.0'), v.software === PLEROMA, ]), + + /** + * Can schedule statuses to be posted at a later time. + * @see POST /api/v1/statuses + * @see {@link https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/} + */ scheduledStatuses: any([ v.software === MASTODON && gte(v.version, '2.7.0'), v.software === PLEROMA, ]), + + /** + * Can bookmark statuses. + * @see POST /api/v1/statuses/:id/bookmark + * @see GET /api/v1/bookmarks + */ bookmarks: any([ v.software === MASTODON && gte(v.compatVersion, '3.1.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), v.software === PIXELFED, ]), + + /** + * Can create, view, and manage lists. + * @see {@link https://docs.joinmastodon.org/methods/timelines/lists/} + * @see GET /api/v1/timelines/list/:list_id + */ lists: any([ v.software === MASTODON && gte(v.compatVersion, '2.1.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), ]), + + /** + * Can display suggested accounts. + * @see {@link https://docs.joinmastodon.org/methods/accounts/suggestions/} + */ suggestions: any([ v.software === MASTODON && gte(v.compatVersion, '2.4.3'), v.software === TRUTHSOCIAL, features.includes('v2_suggestions'), ]), + + /** + * Supports V2 suggested accounts. + * @see GET /api/v2/suggestions + */ suggestionsV2: any([ v.software === MASTODON && gte(v.compatVersion, '3.4.0'), v.software === TRUTHSOCIAL, features.includes('v2_suggestions'), ]), + + /** Whether people who blocked you are visible through the API. */ blockersVisible: features.includes('blockers_visible'), + + /** + * Can display trending hashtags. + * @see GET /api/v1/trends + */ trends: any([ v.software === MASTODON && gte(v.compatVersion, '3.0.0'), v.software === TRUTHSOCIAL, ]), + + /** + * Supports V2 media uploads. + * @see POST /api/v2/media + */ mediaV2: any([ v.software === MASTODON && gte(v.compatVersion, '3.1.3'), // Even though Pleroma supports these endpoints, it has disadvantages // v.software === PLEROMA && gte(v.version, '2.1.0'), ]), - localTimeline: any([ - v.software === MASTODON, - v.software === PLEROMA, - ]), + + /** + * Can display a timeline of all known public statuses. + * Local and Fediverse timelines both use this feature. + * @see GET /api/v1/timelines/public + */ publicTimeline: any([ v.software === MASTODON, v.software === PLEROMA, ]), + + /** + * Legacy DMs timeline where messages are displayed chronologically without groupings. + * @see GET /api/v1/timelines/direct + */ directTimeline: any([ v.software === MASTODON && lt(v.compatVersion, '3.0.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), ]), + + /** + * Mastodon's newer solution for direct messaging. + * @see {@link https://docs.joinmastodon.org/methods/timelines/conversations/} + */ conversations: any([ v.software === MASTODON && gte(v.compatVersion, '2.6.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), v.software === PIXELFED, ]), + + /** + * Ability to add emoji reactions to a status. + * @see PUT /api/v1/pleroma/statuses/:id/reactions/:emoji + * @see GET /api/v1/pleroma/statuses/:id/reactions/:emoji? + * @see DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji + */ emojiReacts: v.software === PLEROMA && gte(v.version, '2.0.0'), + + /** + * The backend allows only RGI ("Recommended for General Interchange") emoji reactions. + * @see PUT /api/v1/pleroma/statuses/:id/reactions/:emoji + */ emojiReactsRGI: v.software === PLEROMA && gte(v.version, '2.2.49'), + + /** + * Allows setting the focal point of a media attachment. + * @see {@link https://docs.joinmastodon.org/methods/statuses/media/} + */ focalPoint: v.software === MASTODON && gte(v.compatVersion, '2.3.0'), + + /** + * Pleroma import API. + * @see POST /api/pleroma/follow_import + * @see POST /api/pleroma/blocks_import + * @see POST /api/pleroma/mutes_import + */ importAPI: v.software === PLEROMA, + + /** + * Pleroma import mutes API. + * @see POST /api/pleroma/mutes_import + */ importMutes: v.software === PLEROMA && gte(v.version, '2.2.0'), + + /** + * Soapbox email list. + * @see POST /api/v1/accounts + * @see PATCH /api/v1/accounts/update_credentials + * @see GET /api/v1/pleroma/admin/email_list/subscribers.csv + * @see GET /api/v1/pleroma/admin/email_list/unsubscribers.csv + * @see GET /api/v1/pleroma/admin/email_list/combined.csv + */ emailList: features.includes('email_list'), + + /** + * Pleroma chats API. + * @see {@link https://docs.pleroma.social/backend/development/API/chats/} + */ chats: v.software === PLEROMA && gte(v.version, '2.1.0'), + + /** + * Paginated chats API. + * @see GET /api/v2/chats + */ chatsV2: v.software === PLEROMA && gte(v.version, '2.3.0'), + + /** + * List of OAuth scopes supported by both Soapbox and the backend. + * @see POST /api/v1/apps + * @see POST /oauth/token + */ scopes: v.software === PLEROMA ? 'read write follow push admin' : 'read write follow push', + + /** Whether the instance federates. */ federating: federation.get('enabled', true) === true, // Assume true unless explicitly false + + /** + * Ability to post statuses in Markdown, BBCode, and HTML. + * @see POST /api/v1/statuses + */ richText: v.software === PLEROMA, + + /** + * Ability to manage account security settings. + * @see POST /api/pleroma/change_password + * @see POST /api/pleroma/change_email + * @see POST /api/pleroma/delete_account + */ securityAPI: any([ v.software === PLEROMA, v.software === TRUTHSOCIAL, ]), + + /** + * Can store client settings in the database. + * @see PATCH /api/v1/accounts/update_credentials + */ settingsStore: any([ v.software === PLEROMA, v.software === TRUTHSOCIAL, ]), + + /** + * Can view and manage ActivityPub aliases through the API. + * @see GET /api/pleroma/aliases + * @see PATCH /api/v1/accounts/update_credentials + */ accountAliasesAPI: v.software === PLEROMA, + + /** + * Can request a password reset email through the API. + * @see POST /auth/password + */ resetPasswordAPI: v.software === PLEROMA, + + /** Whether the accounts who favourited or emoji-reacted to a status can be viewed through the API. */ exposableReactions: features.includes('exposable_reactions'), + + /** + * Ability to subscribe to notifications every time an account posts. + * @see POST /api/v1/pleroma/accounts/:id/subscribe + * @see POST /api/v1/pleroma/accounts/:id/unsubscribe + */ accountSubscriptions: v.software === PLEROMA && gte(v.version, '1.0.0'), + + /** + * Ability to subscribe to notifications every time an account posts. + * @see POST /api/v1/accounts/:id/follow + */ accountNotifies: any([ v.software === MASTODON && gte(v.compatVersion, '3.3.0'), v.software === PLEROMA && gte(v.version, '2.4.50'), ]), + + /** + * Whether the backend allows adding users you don't follow to lists. + * @see POST /api/v1/lists/:id/accounts + */ unrestrictedLists: v.software === PLEROMA, + + /** + * The accounts API allows an acct instead of an ID. + * @see GET /api/v1/accounts/:acct_or_id + */ accountByUsername: v.software === PLEROMA, + + /** + * A directory of discoverable profiles from the instance. + * @see {@link https://docs.joinmastodon.org/methods/instance/directory/} + */ profileDirectory: any([ v.software === MASTODON && gte(v.compatVersion, '3.0.0'), features.includes('profile_directory'), ]), + + /** + * Look up an account by the acct. + * @see GET /api/v1/accounts/lookup + */ accountLookup: any([ v.software === MASTODON && gte(v.compatVersion, '3.4.0'), v.software === PLEROMA && gte(v.version, '2.4.50'), ]), + + /** + * Interact with statuses from another instance while logged-out. + * @see POST /api/v1/pleroma/remote_interaction + */ remoteInteractionsAPI: v.software === PLEROMA && gte(v.version, '2.4.50'), + + /** + * Ability to address recipients of a status explicitly (with `to`). + * @see POST /api/v1/statuses + */ explicitAddressing: any([ v.software === PLEROMA && gte(v.version, '1.0.0'), v.software === TRUTHSOCIAL, ]), + + /** + * Ability to pin other accounts on one's profile. + * @see POST /api/v1/accounts/:id/pin + * @see POST /api/v1/accounts/:id/unpin + * @see GET /api/v1/pleroma/accounts/:id/endorsements + */ accountEndorsements: v.software === PLEROMA && gte(v.version, '2.4.50'), + + /** + * Ability to quote posts in statuses. + * @see POST /api/v1/statuses + */ quotePosts: any([ v.software === PLEROMA && gte(v.version, '2.4.50'), instance.feature_quote === true, ]), + + /** + * Set your birthday and view upcoming birthdays. + * @see GET /api/v1/pleroma/birthdays + * @see POST /api/v1/accounts + * @see PATCH /api/v1/accounts/update_credentials + */ birthdays: v.software === PLEROMA && gte(v.version, '2.4.50'), + + /** + * Sign in with an Ethereum wallet. + * @see POST /oauth/token + */ ethereumLogin: v.software === MITRA, + + /** + * Move followers to a different ActivityPub account. + * @see POST /api/pleroma/move_account + */ accountMoving: v.software === PLEROMA && gte(v.version, '2.4.50'), + + /** + * Add private notes to accounts. + * @see POST /api/v1/accounts/:id/note + * @see GET /api/v1/accounts/relationships + */ notes: any([ v.software === MASTODON && gte(v.compatVersion, '3.2.0'), v.software === PLEROMA && gte(v.version, '2.4.50'), ]), + + /** + * Truth Social trending statuses API. + * @see GET /api/v1/truth/trending/truths + */ trendingTruths: v.software === TRUTHSOCIAL, + + /** + * Trending statuses. + * @see GET /api/v1/trends/statuses + */ trendingStatuses: v.software === MASTODON && gte(v.compatVersion, '3.5.0'), + + /** Truth Social account registration API. */ pepe: v.software === TRUTHSOCIAL, + + /** + * Ability to set one's location on their profile. + * @see PATCH /api/v1/accounts/update_credentials + */ accountLocation: v.software === TRUTHSOCIAL, + + /** + * Ability to set one's website on their profile. + * @see PATCH /api/v1/accounts/update_credentials + */ accountWebsite: v.software === TRUTHSOCIAL, + + /** + * Whether client settings can be retrieved from the API. + * @see GET /api/pleroma/frontend_configurations + */ frontendConfigurations: v.software === PLEROMA, // FIXME: long-term this shouldn't be a feature, @@ -152,8 +441,10 @@ const getInstanceFeatures = (instance: Instance) => { }; }; +/** Features available from a backend */ export type Features = ReturnType; +/** Detect backend features to conditionally render elements */ export const getFeatures = createSelector([ (instance: Instance) => instance, ], (instance): Features => { @@ -161,12 +452,17 @@ export const getFeatures = createSelector([ return Object.assign(features, overrides) as Features; }); +/** Fediverse backend */ interface Backend { + /** Name of the software */ software: string | null, + /** API version number */ version: string, + /** Mastodon API version this backend is compatible with */ compatVersion: string, } +/** Get information about the software from its version string */ export const parseVersion = (version: string): Backend => { const regex = /^([\w.]*)(?: \(compatible; ([\w]*) (.*)\))?$/; const match = regex.exec(version); From 677327336f1083f29fc834dcf535df403bf3cd08 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 23 Apr 2022 15:54:57 -0500 Subject: [PATCH 2/2] Features: sort keys alphabetically --- app/soapbox/utils/features.ts | 495 +++++++++++++++++----------------- 1 file changed, 248 insertions(+), 247 deletions(-) diff --git a/app/soapbox/utils/features.ts b/app/soapbox/utils/features.ts index 49e9f7a2e..947dc4d12 100644 --- a/app/soapbox/utils/features.ts +++ b/app/soapbox/utils/features.ts @@ -1,3 +1,4 @@ +/* eslint sort-keys: "error" */ import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; import { createSelector } from 'reselect'; import gte from 'semver/functions/gte'; @@ -51,49 +52,80 @@ const getInstanceFeatures = (instance: Instance) => { return { /** - * Can upload media attachments to statuses. - * @see POST /api/v1/media - * @see POST /api/v1/statuses + * Can view and manage ActivityPub aliases through the API. + * @see GET /api/pleroma/aliases + * @see PATCH /api/v1/accounts/update_credentials */ - media: true, + accountAliasesAPI: v.software === PLEROMA, /** - * Can set privacy scopes on statuses. - * @see POST /api/v1/statuses + * The accounts API allows an acct instead of an ID. + * @see GET /api/v1/accounts/:acct_or_id */ - privacyScopes: v.software !== TRUTHSOCIAL, + accountByUsername: v.software === PLEROMA, /** - * Can set content warnings on statuses. - * @see POST /api/v1/statuses + * Ability to pin other accounts on one's profile. + * @see POST /api/v1/accounts/:id/pin + * @see POST /api/v1/accounts/:id/unpin + * @see GET /api/v1/pleroma/accounts/:id/endorsements */ - spoilers: v.software !== TRUTHSOCIAL, + accountEndorsements: v.software === PLEROMA && gte(v.version, '2.4.50'), /** - * Can edit and manage timeline filters (aka "muted words"). - * @see {@link https://docs.joinmastodon.org/methods/accounts/filters/} + * Ability to set one's location on their profile. + * @see PATCH /api/v1/accounts/update_credentials */ - filters: v.software !== TRUTHSOCIAL, + accountLocation: v.software === TRUTHSOCIAL, /** - * Can add polls to statuses. - * @see POST /api/v1/statuses + * Look up an account by the acct. + * @see GET /api/v1/accounts/lookup */ - polls: any([ - v.software === MASTODON && gte(v.version, '2.8.0'), - v.software === PLEROMA, + accountLookup: any([ + v.software === MASTODON && gte(v.compatVersion, '3.4.0'), + v.software === PLEROMA && gte(v.version, '2.4.50'), ]), /** - * Can schedule statuses to be posted at a later time. - * @see POST /api/v1/statuses - * @see {@link https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/} + * Move followers to a different ActivityPub account. + * @see POST /api/pleroma/move_account */ - scheduledStatuses: any([ - v.software === MASTODON && gte(v.version, '2.7.0'), - v.software === PLEROMA, + accountMoving: v.software === PLEROMA && gte(v.version, '2.4.50'), + + /** + * Ability to subscribe to notifications every time an account posts. + * @see POST /api/v1/accounts/:id/follow + */ + accountNotifies: any([ + v.software === MASTODON && gte(v.compatVersion, '3.3.0'), + v.software === PLEROMA && gte(v.version, '2.4.50'), ]), + /** + * Ability to subscribe to notifications every time an account posts. + * @see POST /api/v1/pleroma/accounts/:id/subscribe + * @see POST /api/v1/pleroma/accounts/:id/unsubscribe + */ + accountSubscriptions: v.software === PLEROMA && gte(v.version, '1.0.0'), + + /** + * Ability to set one's website on their profile. + * @see PATCH /api/v1/accounts/update_credentials + */ + accountWebsite: v.software === TRUTHSOCIAL, + + /** + * Set your birthday and view upcoming birthdays. + * @see GET /api/v1/pleroma/birthdays + * @see POST /api/v1/accounts + * @see PATCH /api/v1/accounts/update_credentials + */ + birthdays: v.software === PLEROMA && gte(v.version, '2.4.50'), + + /** Whether people who blocked you are visible through the API. */ + blockersVisible: features.includes('blockers_visible'), + /** * Can bookmark statuses. * @see POST /api/v1/statuses/:id/bookmark @@ -106,66 +138,30 @@ const getInstanceFeatures = (instance: Instance) => { ]), /** - * Can create, view, and manage lists. - * @see {@link https://docs.joinmastodon.org/methods/timelines/lists/} - * @see GET /api/v1/timelines/list/:list_id + * Pleroma chats API. + * @see {@link https://docs.pleroma.social/backend/development/API/chats/} */ - lists: any([ - v.software === MASTODON && gte(v.compatVersion, '2.1.0'), + chats: v.software === PLEROMA && gte(v.version, '2.1.0'), + + /** + * Paginated chats API. + * @see GET /api/v2/chats + */ + chatsV2: v.software === PLEROMA && gte(v.version, '2.3.0'), + + /** + * Mastodon's newer solution for direct messaging. + * @see {@link https://docs.joinmastodon.org/methods/timelines/conversations/} + */ + conversations: any([ + v.software === MASTODON && gte(v.compatVersion, '2.6.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), + v.software === PIXELFED, ]), - /** - * Can display suggested accounts. - * @see {@link https://docs.joinmastodon.org/methods/accounts/suggestions/} - */ - suggestions: any([ - v.software === MASTODON && gte(v.compatVersion, '2.4.3'), - v.software === TRUTHSOCIAL, - features.includes('v2_suggestions'), - ]), - - /** - * Supports V2 suggested accounts. - * @see GET /api/v2/suggestions - */ - suggestionsV2: any([ - v.software === MASTODON && gte(v.compatVersion, '3.4.0'), - v.software === TRUTHSOCIAL, - features.includes('v2_suggestions'), - ]), - - /** Whether people who blocked you are visible through the API. */ - blockersVisible: features.includes('blockers_visible'), - - /** - * Can display trending hashtags. - * @see GET /api/v1/trends - */ - trends: any([ - v.software === MASTODON && gte(v.compatVersion, '3.0.0'), - v.software === TRUTHSOCIAL, - ]), - - /** - * Supports V2 media uploads. - * @see POST /api/v2/media - */ - mediaV2: any([ - v.software === MASTODON && gte(v.compatVersion, '3.1.3'), - // Even though Pleroma supports these endpoints, it has disadvantages - // v.software === PLEROMA && gte(v.version, '2.1.0'), - ]), - - /** - * Can display a timeline of all known public statuses. - * Local and Fediverse timelines both use this feature. - * @see GET /api/v1/timelines/public - */ - publicTimeline: any([ - v.software === MASTODON, - v.software === PLEROMA, - ]), + // FIXME: long-term this shouldn't be a feature, + // but for now we want it to be overrideable in the build + darkMode: true, /** * Legacy DMs timeline where messages are displayed chronologically without groupings. @@ -177,14 +173,14 @@ const getInstanceFeatures = (instance: Instance) => { ]), /** - * Mastodon's newer solution for direct messaging. - * @see {@link https://docs.joinmastodon.org/methods/timelines/conversations/} + * Soapbox email list. + * @see POST /api/v1/accounts + * @see PATCH /api/v1/accounts/update_credentials + * @see GET /api/v1/pleroma/admin/email_list/subscribers.csv + * @see GET /api/v1/pleroma/admin/email_list/unsubscribers.csv + * @see GET /api/v1/pleroma/admin/email_list/combined.csv */ - conversations: any([ - v.software === MASTODON && gte(v.compatVersion, '2.6.0'), - v.software === PLEROMA && gte(v.version, '0.9.9'), - v.software === PIXELFED, - ]), + emailList: features.includes('email_list'), /** * Ability to add emoji reactions to a status. @@ -200,12 +196,45 @@ const getInstanceFeatures = (instance: Instance) => { */ emojiReactsRGI: v.software === PLEROMA && gte(v.version, '2.2.49'), + /** + * Sign in with an Ethereum wallet. + * @see POST /oauth/token + */ + ethereumLogin: v.software === MITRA, + + /** + * Ability to address recipients of a status explicitly (with `to`). + * @see POST /api/v1/statuses + */ + explicitAddressing: any([ + v.software === PLEROMA && gte(v.version, '1.0.0'), + v.software === TRUTHSOCIAL, + ]), + + /** Whether the accounts who favourited or emoji-reacted to a status can be viewed through the API. */ + exposableReactions: features.includes('exposable_reactions'), + + /** Whether the instance federates. */ + federating: federation.get('enabled', true) === true, // Assume true unless explicitly false + + /** + * Can edit and manage timeline filters (aka "muted words"). + * @see {@link https://docs.joinmastodon.org/methods/accounts/filters/} + */ + filters: v.software !== TRUTHSOCIAL, + /** * Allows setting the focal point of a media attachment. * @see {@link https://docs.joinmastodon.org/methods/statuses/media/} */ focalPoint: v.software === MASTODON && gte(v.compatVersion, '2.3.0'), + /** + * Whether client settings can be retrieved from the API. + * @see GET /api/pleroma/frontend_configurations + */ + frontendConfigurations: v.software === PLEROMA, + /** * Pleroma import API. * @see POST /api/pleroma/follow_import @@ -221,26 +250,115 @@ const getInstanceFeatures = (instance: Instance) => { importMutes: v.software === PLEROMA && gte(v.version, '2.2.0'), /** - * Soapbox email list. - * @see POST /api/v1/accounts - * @see PATCH /api/v1/accounts/update_credentials - * @see GET /api/v1/pleroma/admin/email_list/subscribers.csv - * @see GET /api/v1/pleroma/admin/email_list/unsubscribers.csv - * @see GET /api/v1/pleroma/admin/email_list/combined.csv + * Can create, view, and manage lists. + * @see {@link https://docs.joinmastodon.org/methods/timelines/lists/} + * @see GET /api/v1/timelines/list/:list_id */ - emailList: features.includes('email_list'), + lists: any([ + v.software === MASTODON && gte(v.compatVersion, '2.1.0'), + v.software === PLEROMA && gte(v.version, '0.9.9'), + ]), /** - * Pleroma chats API. - * @see {@link https://docs.pleroma.social/backend/development/API/chats/} + * Can upload media attachments to statuses. + * @see POST /api/v1/media + * @see POST /api/v1/statuses */ - chats: v.software === PLEROMA && gte(v.version, '2.1.0'), + media: true, /** - * Paginated chats API. - * @see GET /api/v2/chats + * Supports V2 media uploads. + * @see POST /api/v2/media */ - chatsV2: v.software === PLEROMA && gte(v.version, '2.3.0'), + mediaV2: any([ + v.software === MASTODON && gte(v.compatVersion, '3.1.3'), + // Even though Pleroma supports these endpoints, it has disadvantages + // v.software === PLEROMA && gte(v.version, '2.1.0'), + ]), + + /** + * Add private notes to accounts. + * @see POST /api/v1/accounts/:id/note + * @see GET /api/v1/accounts/relationships + */ + notes: any([ + v.software === MASTODON && gte(v.compatVersion, '3.2.0'), + v.software === PLEROMA && gte(v.version, '2.4.50'), + ]), + + /** Truth Social account registration API. */ + pepe: v.software === TRUTHSOCIAL, + + /** + * Can add polls to statuses. + * @see POST /api/v1/statuses + */ + polls: any([ + v.software === MASTODON && gte(v.version, '2.8.0'), + v.software === PLEROMA, + ]), + + /** + * Can set privacy scopes on statuses. + * @see POST /api/v1/statuses + */ + privacyScopes: v.software !== TRUTHSOCIAL, + + /** + * A directory of discoverable profiles from the instance. + * @see {@link https://docs.joinmastodon.org/methods/instance/directory/} + */ + profileDirectory: any([ + v.software === MASTODON && gte(v.compatVersion, '3.0.0'), + features.includes('profile_directory'), + ]), + + /** + * Can display a timeline of all known public statuses. + * Local and Fediverse timelines both use this feature. + * @see GET /api/v1/timelines/public + */ + publicTimeline: any([ + v.software === MASTODON, + v.software === PLEROMA, + ]), + + /** + * Ability to quote posts in statuses. + * @see POST /api/v1/statuses + */ + quotePosts: any([ + v.software === PLEROMA && gte(v.version, '2.4.50'), + instance.feature_quote === true, + ]), + + /** + * Interact with statuses from another instance while logged-out. + * @see POST /api/v1/pleroma/remote_interaction + */ + remoteInteractionsAPI: v.software === PLEROMA && gte(v.version, '2.4.50'), + + /** + * Can request a password reset email through the API. + * @see POST /auth/password + */ + resetPasswordAPI: v.software === PLEROMA, + + /** + * Ability to post statuses in Markdown, BBCode, and HTML. + * @see POST /api/v1/statuses + */ + richText: v.software === PLEROMA, + + /** + * Can schedule statuses to be posted at a later time. + * @see POST /api/v1/statuses + * @see {@link https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/} + */ + scheduledStatuses: any([ + v.software === MASTODON && gte(v.version, '2.7.0'), + v.software === PLEROMA, + ]), /** * List of OAuth scopes supported by both Soapbox and the backend. @@ -249,15 +367,6 @@ const getInstanceFeatures = (instance: Instance) => { */ scopes: v.software === PLEROMA ? 'read write follow push admin' : 'read write follow push', - /** Whether the instance federates. */ - federating: federation.get('enabled', true) === true, // Assume true unless explicitly false - - /** - * Ability to post statuses in Markdown, BBCode, and HTML. - * @see POST /api/v1/statuses - */ - richText: v.software === PLEROMA, - /** * Ability to manage account security settings. * @see POST /api/pleroma/change_password @@ -279,128 +388,36 @@ const getInstanceFeatures = (instance: Instance) => { ]), /** - * Can view and manage ActivityPub aliases through the API. - * @see GET /api/pleroma/aliases - * @see PATCH /api/v1/accounts/update_credentials - */ - accountAliasesAPI: v.software === PLEROMA, - - /** - * Can request a password reset email through the API. - * @see POST /auth/password - */ - resetPasswordAPI: v.software === PLEROMA, - - /** Whether the accounts who favourited or emoji-reacted to a status can be viewed through the API. */ - exposableReactions: features.includes('exposable_reactions'), - - /** - * Ability to subscribe to notifications every time an account posts. - * @see POST /api/v1/pleroma/accounts/:id/subscribe - * @see POST /api/v1/pleroma/accounts/:id/unsubscribe - */ - accountSubscriptions: v.software === PLEROMA && gte(v.version, '1.0.0'), - - /** - * Ability to subscribe to notifications every time an account posts. - * @see POST /api/v1/accounts/:id/follow - */ - accountNotifies: any([ - v.software === MASTODON && gte(v.compatVersion, '3.3.0'), - v.software === PLEROMA && gte(v.version, '2.4.50'), - ]), - - /** - * Whether the backend allows adding users you don't follow to lists. - * @see POST /api/v1/lists/:id/accounts - */ - unrestrictedLists: v.software === PLEROMA, - - /** - * The accounts API allows an acct instead of an ID. - * @see GET /api/v1/accounts/:acct_or_id - */ - accountByUsername: v.software === PLEROMA, - - /** - * A directory of discoverable profiles from the instance. - * @see {@link https://docs.joinmastodon.org/methods/instance/directory/} - */ - profileDirectory: any([ - v.software === MASTODON && gte(v.compatVersion, '3.0.0'), - features.includes('profile_directory'), - ]), - - /** - * Look up an account by the acct. - * @see GET /api/v1/accounts/lookup - */ - accountLookup: any([ - v.software === MASTODON && gte(v.compatVersion, '3.4.0'), - v.software === PLEROMA && gte(v.version, '2.4.50'), - ]), - - /** - * Interact with statuses from another instance while logged-out. - * @see POST /api/v1/pleroma/remote_interaction - */ - remoteInteractionsAPI: v.software === PLEROMA && gte(v.version, '2.4.50'), - - /** - * Ability to address recipients of a status explicitly (with `to`). + * Can set content warnings on statuses. * @see POST /api/v1/statuses */ - explicitAddressing: any([ - v.software === PLEROMA && gte(v.version, '1.0.0'), + spoilers: v.software !== TRUTHSOCIAL, + + /** + * Can display suggested accounts. + * @see {@link https://docs.joinmastodon.org/methods/accounts/suggestions/} + */ + suggestions: any([ + v.software === MASTODON && gte(v.compatVersion, '2.4.3'), v.software === TRUTHSOCIAL, + features.includes('v2_suggestions'), ]), /** - * Ability to pin other accounts on one's profile. - * @see POST /api/v1/accounts/:id/pin - * @see POST /api/v1/accounts/:id/unpin - * @see GET /api/v1/pleroma/accounts/:id/endorsements + * Supports V2 suggested accounts. + * @see GET /api/v2/suggestions */ - accountEndorsements: v.software === PLEROMA && gte(v.version, '2.4.50'), - - /** - * Ability to quote posts in statuses. - * @see POST /api/v1/statuses - */ - quotePosts: any([ - v.software === PLEROMA && gte(v.version, '2.4.50'), - instance.feature_quote === true, + suggestionsV2: any([ + v.software === MASTODON && gte(v.compatVersion, '3.4.0'), + v.software === TRUTHSOCIAL, + features.includes('v2_suggestions'), ]), /** - * Set your birthday and view upcoming birthdays. - * @see GET /api/v1/pleroma/birthdays - * @see POST /api/v1/accounts - * @see PATCH /api/v1/accounts/update_credentials + * Trending statuses. + * @see GET /api/v1/trends/statuses */ - birthdays: v.software === PLEROMA && gte(v.version, '2.4.50'), - - /** - * Sign in with an Ethereum wallet. - * @see POST /oauth/token - */ - ethereumLogin: v.software === MITRA, - - /** - * Move followers to a different ActivityPub account. - * @see POST /api/pleroma/move_account - */ - accountMoving: v.software === PLEROMA && gte(v.version, '2.4.50'), - - /** - * Add private notes to accounts. - * @see POST /api/v1/accounts/:id/note - * @see GET /api/v1/accounts/relationships - */ - notes: any([ - v.software === MASTODON && gte(v.compatVersion, '3.2.0'), - v.software === PLEROMA && gte(v.version, '2.4.50'), - ]), + trendingStatuses: v.software === MASTODON && gte(v.compatVersion, '3.5.0'), /** * Truth Social trending statuses API. @@ -409,35 +426,19 @@ const getInstanceFeatures = (instance: Instance) => { trendingTruths: v.software === TRUTHSOCIAL, /** - * Trending statuses. - * @see GET /api/v1/trends/statuses + * Can display trending hashtags. + * @see GET /api/v1/trends */ - trendingStatuses: v.software === MASTODON && gte(v.compatVersion, '3.5.0'), - - /** Truth Social account registration API. */ - pepe: v.software === TRUTHSOCIAL, + trends: any([ + v.software === MASTODON && gte(v.compatVersion, '3.0.0'), + v.software === TRUTHSOCIAL, + ]), /** - * Ability to set one's location on their profile. - * @see PATCH /api/v1/accounts/update_credentials + * Whether the backend allows adding users you don't follow to lists. + * @see POST /api/v1/lists/:id/accounts */ - accountLocation: v.software === TRUTHSOCIAL, - - /** - * Ability to set one's website on their profile. - * @see PATCH /api/v1/accounts/update_credentials - */ - accountWebsite: v.software === TRUTHSOCIAL, - - /** - * Whether client settings can be retrieved from the API. - * @see GET /api/pleroma/frontend_configurations - */ - frontendConfigurations: v.software === PLEROMA, - - // FIXME: long-term this shouldn't be a feature, - // but for now we want it to be overrideable in the build - darkMode: true, + unrestrictedLists: v.software === PLEROMA, }; }; @@ -469,17 +470,17 @@ export const parseVersion = (version: string): Backend => { if (match) { return { + compatVersion: match[1], software: match[2] || MASTODON, version: match[3] || match[1], - compatVersion: match[1], }; } else { // If we can't parse the version, this is a new and exotic backend. // Fall back to minimal featureset. return { + compatVersion: '0.0.0', software: null, version: '0.0.0', - compatVersion: '0.0.0', }; } };