diff --git a/packages/pl-api/lib/client.ts b/packages/pl-api/lib/client.ts index 77b4bcde1..408b5d805 100644 --- a/packages/pl-api/lib/client.ts +++ b/packages/pl-api/lib/client.ts @@ -221,10 +221,13 @@ import type { GetRebloggedByParams, GetStatusContextParams, GetStatusesParams, + GetStatusMentionedUsersParams, GetStatusParams, GetStatusQuotesParams, + GetStatusReferencesParams, } from './params/statuses'; import type { + AntennaTimelineParams, BubbleTimelineParams, GetConversationsParams, GroupTimelineParams, @@ -603,6 +606,27 @@ class PlApiClient { return v.parse(filteredArray(listSchema), response.json); }, + /** + * Get antennas containing this account + * User antennas that you have added this account to. + * Requires features{@link Features['antennas']}. + */ + getAccountAntennas: async (accountId: string) => { + const response = await this.request(`/api/v1/accounts/${accountId}/antennas`); + + return v.parse(filteredArray(antennaSchema), response.json); + }, + + /** + * Get antennas excluding this account + * Requires features{@link Features['antennas']}. + */ + getAccountExcludeAntennas: async (accountId: string) => { + const response = await this.request(`/api/v1/accounts/${accountId}/exclude_antennas`); + + return v.parse(filteredArray(antennaSchema), response.json); + }, + /** * Follow account * Follow the given account. Can also be used to update whether to show reblogs or enable notifications. @@ -2248,6 +2272,12 @@ class PlApiClient { return v.parse(statusSchema, response.json); }, + + getStatusReferences: async (statusId: string, params?: GetStatusReferencesParams) => + this.#paginatedGet(`/api/v1/statuses/${statusId}/referred_by`, { params }, statusSchema), + + getStatusMentionedUsers: async (statusId: string, params?: GetStatusMentionedUsersParams) => + this.#paginatedGet(`/api/v1/statuses/${statusId}/mentioned_by`, { params }, accountSchema), }; public readonly media = { @@ -2459,6 +2489,13 @@ class PlApiClient { */ bubbleTimeline: async (params?: BubbleTimelineParams) => this.#paginatedGet('/api/v1/timelines/bubble', { params }, statusSchema), + + /** + * View antennatimeline + * Requires features{@link Features['antennas']}. + */ + antennaTimeline: (antennaId: string, params?: AntennaTimelineParams) => + this.#paginatedGet(`/api/v1/timelines/list/${antennaId}`, { params }, statusSchema), }; public readonly lists = { @@ -4495,6 +4532,15 @@ class PlApiClient { return v.parse(filteredArray(antennaSchema), response.json); }, + /** + * Requires features{@link Features['antennas']}. + */ + getAntennas: async (antennaId: string) => { + const response = await this.request(`/api/v1/antennas/${antennaId}`); + + return v.parse(antennaSchema, response.json); + }, + /** * Requires features{@link Features['antennas']}. */ @@ -4517,9 +4563,255 @@ class PlApiClient { * Requires features{@link Features['antennas']}. */ deleteAntenna: async (antennaId: string) => { - const response = await this.request(`/api/v1/antennas/${antennaId}`, { method: 'DELETE' }); + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}`, { method: 'DELETE' }); - return response.json as {}; + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + getAntennaAccounts: async (antennaId: string) => { + const response = await this.request(`/api/v1/antennas/${antennaId}/accounts`); + + return v.parse(filteredArray(accountSchema), response.json); + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaAccount: async (antennaId: string, accountId: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/accounts`, { + method: 'POST', + body: { account_ids: [accountId] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaAccount: async (antennaId: string, accountId: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/accounts`, { + method: 'DELETE', + body: { account_ids: [accountId] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + getAntennaExcludeAccounts: async (antennaId: string) => { + const response = await this.request(`/api/v1/antennas/${antennaId}/exclude_accounts`); + + return v.parse(filteredArray(accountSchema), response.json); + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaExcludeAccount: async (antennaId: string, accountId: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_accounts`, { + method: 'POST', + body: { account_ids: [accountId] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaExcludeAccount: async (antennaId: string, accountId: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_accounts`, { + method: 'DELETE', + body: { account_ids: [accountId] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + getAntennaDomains: async (antennaId: string) => { + const response = await this.request(`/api/v1/antennas/${antennaId}/domains`); + + return v.parse(v.object({ + domains: filteredArray(v.string()), + exclude_domains: filteredArray(v.string()), + }), response.json); + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaDomain: async (antennaId: string, domain: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/domains`, { + method: 'POST', + body: { domains: [domain] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaDomain: async (antennaId: string, domain: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/domains`, { + method: 'DELETE', + body: { domains: [domain] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaExcludeDomain: async (antennaId: string, domain: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_domains`, { + method: 'POST', + body: { domains: [domain] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaExcludeDomain: async (antennaId: string, domain: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_domains`, { + method: 'DELETE', + body: { domains: [domain] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + getAntennaKeywords: async (antennaId: string) => { + const response = await this.request(`/api/v1/antennas/${antennaId}/keywords`); + + return v.parse(v.object({ + keywords: filteredArray(v.string()), + exclude_keywords: filteredArray(v.string()), + }), response.json); + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaKeyword: async (antennaId: string, keyword: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/keywords`, { + method: 'POST', + body: { keywords: [keyword] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaKeyword: async (antennaId: string, keyword: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/keywords`, { + method: 'DELETE', + body: { keywords: [keyword] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaExcludeKeyword: async (antennaId: string, keyword: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_keywords`, { + method: 'POST', + body: { keywords: [keyword] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaExcludeKeyword: async (antennaId: string, keyword: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_keywords`, { + method: 'DELETE', + body: { keywords: [keyword] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + getAntennaTags: async (antennaId: string) => { + const response = await this.request(`/api/v1/antennas/${antennaId}/tags`); + + return v.parse(v.object({ + tags: filteredArray(v.string()), + exclude_tags: filteredArray(v.string()), + }), response.json); + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaTag: async (antennaId: string, tag: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/tags`, { + method: 'POST', + body: { tags: [tag] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaTag: async (antennaId: string, tag: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/tags`, { + method: 'DELETE', + body: { tags: [tag] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + addAntennaExcludeTag: async (antennaId: string, tag: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_tags`, { + method: 'POST', + body: { tags: [tag] }, + }); + + return response.json; + }, + + /** + * Requires features{@link Features['antennas']}. + */ + removeAntennaExcludeTag: async (antennaId: string, tag: string) => { + const response = await this.request<{}>(`/api/v1/antennas/${antennaId}/exclude_tags`, { + method: 'DELETE', + body: { tags: [tag] }, + }); + + return response.json; }, }; diff --git a/packages/pl-api/lib/entities/bookmark-folder.ts b/packages/pl-api/lib/entities/bookmark-folder.ts index e4e063f48..77dc5fd75 100644 --- a/packages/pl-api/lib/entities/bookmark-folder.ts +++ b/packages/pl-api/lib/entities/bookmark-folder.ts @@ -3,12 +3,15 @@ import * as v from 'valibot'; /** * @category Schemas */ -const bookmarkFolderSchema = v.object({ +const bookmarkFolderSchema = v.pipe(v.any(), v.transform((data) => ({ + name: data.title, + ...data, +})), v.object({ id: v.pipe(v.unknown(), v.transform(String)), name: v.fallback(v.string(), ''), emoji: v.fallback(v.nullable(v.string()), null), emoji_url: v.fallback(v.nullable(v.string()), null), -}); +})); /** * @category Entity types diff --git a/packages/pl-api/lib/entities/context.ts b/packages/pl-api/lib/entities/context.ts index bec10638d..b4ad24b4c 100644 --- a/packages/pl-api/lib/entities/context.ts +++ b/packages/pl-api/lib/entities/context.ts @@ -9,6 +9,7 @@ import { statusSchema } from './status'; const contextSchema = v.object({ ancestors: v.array(statusSchema), descendants: v.array(statusSchema), + references: v.fallback(v.array(statusSchema), []), }); /** diff --git a/packages/pl-api/lib/features.ts b/packages/pl-api/lib/features.ts index 2339d00b9..71b19d73a 100644 --- a/packages/pl-api/lib/features.ts +++ b/packages/pl-api/lib/features.ts @@ -271,6 +271,8 @@ const getFeatures = (instance: Instance) => { */ announcementsReactions: v.software === MASTODON, + kmyblue_antenna: instance.api_versions['kmyblue_antenna.fedibird.pl-api'] >= 1, + /** * Set your birthday and view upcoming birthdays. * @see GET /api/v1/pleroma/birthdays diff --git a/packages/pl-api/lib/params/statuses.ts b/packages/pl-api/lib/params/statuses.ts index 5e5bdb03f..2fad0b014 100644 --- a/packages/pl-api/lib/params/statuses.ts +++ b/packages/pl-api/lib/params/statuses.ts @@ -156,6 +156,16 @@ type EditStatusParams = (CreateStatusWithContent | CreateStatusWithMedia) & Edit */ type GetStatusQuotesParams = PaginationParams; +/** + * @category Request params + */ +type GetStatusReferencesParams = PaginationParams; + +/** + * @category Request params + */ +type GetStatusMentionedUsersParams = PaginationParams; + export type { CreateStatusParams, GetStatusParams, @@ -165,5 +175,7 @@ export type { GetFavouritedByParams, EditStatusParams, GetStatusQuotesParams, + GetStatusReferencesParams, + GetStatusMentionedUsersParams, }; diff --git a/packages/pl-api/lib/params/timelines.ts b/packages/pl-api/lib/params/timelines.ts index 34e880ca6..f74e719eb 100644 --- a/packages/pl-api/lib/params/timelines.ts +++ b/packages/pl-api/lib/params/timelines.ts @@ -47,6 +47,11 @@ type LinkTimelineParams = PaginationParams & WithMutedParam & LanguageParam; */ type ListTimelineParams = PaginationParams & WithMutedParam & OnlyEventsParam & LanguageParam; +/** + * @category Request params + */ +type AntennaTimelineParams = PaginationParams & WithMutedParam & OnlyEventsParam & LanguageParam; + /** * @category Request params */ @@ -92,4 +97,5 @@ export type { SaveMarkersParams, GroupTimelineParams, BubbleTimelineParams, + AntennaTimelineParams, };