pl-api: implement most of Mastodon 4.3.0 api

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-11-01 17:30:32 +01:00
parent 27c77861c5
commit 199c43d241
13 changed files with 112 additions and 22 deletions

View file

@ -2649,6 +2649,44 @@ class PlApiClient {
return response.json as {};
},
/**
* Accept multiple notification requests
* Accepts multiple notification requests, which merges the filtered notifications from those users back into the main notifications and accepts any future notification from them.
* @see {@link https://docs.joinmastodon.org/methods/notifications/#accept-multiple-requests}
* Requires features{@link Features['notificationsRequestsAcceptMultiple']}.
*/
acceptMultipleNotificationRequests: async (notificationRequestIds: Array<string>) => {
const response = await this.request('/api/v1/notifications/requests/accept', { method: 'POST', body: { id: notificationRequestIds } });
return response.json as {};
},
/**
* Dismiss multiple notification requests
* Dismiss multiple notification requests, which hides them and prevent them from contributing to the pending notification requests count.
* @see {@link https://docs.joinmastodon.org/methods/notifications/#dismiss-multiple-requests}
* Requires features{@link Features['notificationsRequestsAcceptMultiple']}.
*/
dismissMultipleNotificationRequests: async (notificationRequestIds: Array<string>) => {
const response = await this.request('/api/v1/notifications/requests/dismiss', { method: 'POST', body: { id: notificationRequestIds } });
return response.json as {};
},
/**
* Check if accepted notification requests have been merged
* Check whether accepted notification requests have been merged. Accepting notification requests schedules a background job to merge the filtered notifications back into the normal notification list. When that process has finished, the client should refresh the notifications list at its earliest convenience. This is communicated by the `notifications_merged` streaming event but can also be polled using this endpoint.
* @see {@link https://docs.joinmastodon.org/methods/notifications/#requests-merged}
* Requires features{@link Features['notificationsRequestsAcceptMultiple']}.
*/
checkNotificationRequestsMerged: async () => {
const response = await this.request('/api/v1/notifications/requests/merged');
return v.parse(v.object({
merged: v.boolean(),
}), response.json);
},
/**
* An endpoint to delete multiple statuses by IDs.
*
@ -2663,6 +2701,8 @@ class PlApiClient {
return response.json as {};
},
};
public readonly pushNotifications = {

View file

@ -1,21 +1,29 @@
import * as v from 'valibot';
import { filteredArray } from './utils';
/**
* @category Schemas
* @see {@link https://docs.joinmastodon.org/entities/Application/}
*/
const applicationSchema = v.object({
const applicationSchema = v.pipe(v.any(), v.transform((application) => ({
redirect_uris: [application.redirect_uri],
...application,
})), v.object({
name: v.fallback(v.string(), ''),
website: v.fallback(v.optional(v.string()), undefined),
client_id: v.fallback(v.optional(v.string()), undefined),
client_secret: v.fallback(v.optional(v.string()), undefined),
redirect_uri: v.fallback(v.optional(v.string()), undefined),
client_secret_expires_at: v.fallback(v.optional(v.string()), undefined),
redirect_uris: filteredArray(v.string()),
id: v.fallback(v.optional(v.string()), undefined),
/** @deprecated */
redirect_uri: v.fallback(v.optional(v.string()), undefined),
/** @deprecated */
vapid_key: v.fallback(v.optional(v.string()), undefined),
});
}));
type Application = v.InferOutput<typeof applicationSchema>;

View file

@ -0,0 +1,17 @@
import * as v from 'valibot';
import { accountSchema } from './account';
/**
* @category Schemas
* @see {@link https://docs.joinmastodon.org/entities/PreviewCardAuthor/}
*/
const previewCardAuthorSchema = v.object({
name: v.string(),
url: v.pipe(v.string(), v.url()),
account: v.fallback(v.nullable(accountSchema), null),
});
type PreviewCardAuthor = v.InferOutput<typeof previewCardAuthorSchema>;
export { previewCardAuthorSchema, type PreviewCardAuthor };

View file

@ -1,12 +1,18 @@
import * as v from 'valibot';
import { previewCardAuthorSchema } from './preview-card-author';
import { filteredArray } from './utils';
/**
* @category Schemas
* @see {@link https://docs.joinmastodon.org/entities/PreviewCard/}
*/
const previewCardSchema = v.object({
/** @deprecated */
author_name: v.fallback(v.string(), ''),
/** @deprecated */
author_url: v.fallback(v.pipe(v.string(), v.url()), ''),
authors: filteredArray(previewCardAuthorSchema),
blurhash: v.fallback(v.nullable(v.string()), null),
description: v.fallback(v.string(), ''),
embed_url: v.fallback(v.pipe(v.string(), v.url()), ''),

View file

@ -99,6 +99,11 @@ const markerStreamingEventSchema = v.object({
payload: v.pipe(v.any(), v.transform((payload: any) => JSON.parse(payload)), markersSchema),
});
const notificationsMergedEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('notifications_merged'),
});
/**
* @category Schemas
* @see {@link https://docs.joinmastodon.org/methods/streaming/#events}
@ -121,6 +126,7 @@ const streamingEventSchema: v.BaseSchema<any, StreamingEvent, v.BaseIssue<unknow
followRelationshipsUpdateStreamingEventSchema,
respondStreamingEventSchema,
markerStreamingEventSchema,
notificationsMergedEventSchema,
]),
) as any;
@ -136,6 +142,7 @@ type StreamingEvent = v.InferOutput<
| typeof followRelationshipsUpdateStreamingEventSchema
| typeof respondStreamingEventSchema
| typeof markerStreamingEventSchema
| typeof notificationsMergedEventSchema
>;
export {

View file

@ -896,6 +896,12 @@ const getFeatures = (instance: Instance) => {
*/
notificationsPolicy: instance.api_versions.mastodon >= 1,
/**
* @see POST /api/v1/notifications/requests/accept
* @see POST /api/v1/notifications/requests/dismiss
*/
notificationsRequestsAcceptMultiple: instance.api_versions.mastodon >= 1,
pleromaAdminAccounts: v.software === PLEROMA,
/**

View file

@ -37,7 +37,7 @@ interface FollowAccountParams {
notify?: boolean;
/**
* Array of String (ISO 639-1 language two-letter code). Filter received statuses for these languages. If not provided, you will receive this accounts posts in all languages.
* Requires `features.followAccountLanguages`.
* Requires features{@link Features['followAccountLanguages']}.
*/
languages?: string[];
}

View file

@ -13,7 +13,7 @@ interface WithMutedParam {
/**
* Boolean. Also show statuses from muted users. Default to false.
*
* Requires `features.timelinesWithMuted`.
* Requires features{@link Features['timelinesWithMuted']}.
*/
with_muted?: boolean;
}
@ -35,7 +35,7 @@ interface OnlyEventsParam {
/**
* Boolean. Filter out statuses without events.
*
* Requires `features.events`.
* Requires features{@link Features['events']}.
*/
only_events?: boolean;
}
@ -44,7 +44,7 @@ interface LanguageParam {
/**
* Fetch a translation in given language
*
* Requires `features.fetchStatusesWithTranslation`.
* Requires features{@link Features['fetchStatusesWithTranslation']}.
*/
language?: string;
}

View file

@ -6,7 +6,7 @@ import type { PaginationParams } from './common';
interface GetBookmarksParams extends PaginationParams {
/**
* Bookmark folder ID
* Requires `features.bookmarkFolders`.
* Requires features{@link Features['bookmarkFolders']}.
*/
folder_id?: string;
}

View file

@ -10,9 +10,14 @@ interface GetNotificationParams extends PaginationParams {
exclude_types?: string[];
/** Return only notifications received from the specified account. */
account_id?: string;
/**
* Whether to include notifications filtered by the users NotificationPolicy. Defaults to false.
* Requires features.{@link Features['notificationsPolicy']}.
*/
include_filtered?: boolean;
/**
* will exclude the notifications for activities with the given visibilities. The parameter accepts an array of visibility types (`public`, `unlisted`, `private`, `direct`).
* Requires `features.notificationsExcludeVisibilities`.
* Requires features{@link Features['notificationsExcludeVisibilities']}.
*/
exclude_visibilities?: string[];
}

View file

@ -106,17 +106,18 @@ interface UpdateCredentialsParams {
/**
* Description of avatar image, for alt-text.
* Requires `features.accountAvatarDescription`.
*
* Requires features{@link Features['accountAvatarDescription']}.
*/
avatar_description?: boolean;
/**
* Description of header image, for alt-text.
* Requires `features.accountAvatarDescription`.
* Requires features{@link Features['accountAvatarDescription']}.
*/
header_description?: boolean;
/**
* Enable RSS feed for this account's Public posts at `/[username]/feed.rss`
* Requires `features.accountEnableRss`.
* Requires features{@link Features['accountEnableRss']}.
*/
enable_rss?: boolean;
}

View file

@ -46,8 +46,8 @@ interface CreateStatusOptionalParams {
spoiler_text?: string;
/**
* String. Sets the visibility of the posted status to `public`, `unlisted`, `private`, `direct`.
* `local` requires `features.createStatusLocalScope`.
* `list:LIST_ID` requires `features.createStatusListScope`.
* `local` Requires features{@link Features['createStatusLocalScope']}.
* `list:LIST_ID` Requires features{@link Features['createStatusListScope']}.
*/
visibility?: string;
/** String. ISO 639 language code for this status. */
@ -57,7 +57,7 @@ interface CreateStatusOptionalParams {
/**
* boolean, if set to true the post won't be actually posted, but the status entity would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
* Requires `features.createStatusPreview`.
* Requires features{@link Features['createStatusPreview']}.
*/
preview?: boolean;
/**
@ -66,22 +66,22 @@ interface CreateStatusOptionalParams {
content_type?: string;
/**
* A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for post visibility are not affected by this and will still apply.
* Requires `features.createStatusExplicitAddressing`.
* Requires features{@link Features['createStatusExplicitAddressing']}.
*/
to?: string[];
/**
* The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour.
* Requires `features.createStatusExpiration`.
* Requires features{@link Features['createStatusExpiration']}.
*/
expires_in?: number;
/**
* Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`.
* Requires `features.createStatusReplyToConversation`.
* Requires features{@link Features['createStatusReplyToConversation']}.
*/
in_reply_to_conversation_id?: string;
/**
* ID of the status being quoted, if any.
* Requires `features.quotePosts`.
* Requires features{@link Features['quotePosts']}.
*/
quote_id?: string;
@ -108,7 +108,7 @@ type CreateStatusParams = (CreateStatusWithContent | CreateStatusWithMedia) & Cr
* @category Request params
*/
interface LanguageParam {
/** Attach translated version of a post. Requires `features.autoTranslate`. */
/** Attach translated version of a post. Requires features{@link Features['autoTranslate']}. */
language?: string;
}

View file

@ -11,7 +11,7 @@ interface PublicTimelineParams extends PaginationParams, WithMutedParam, OnlyEve
/**
* Boolean. Show only statuses from the given domain.
*
* Requires `features.instanceTimeline`.
* Requires features{@link Features['instanceTimeline']}.
*/
instance?: string;
}
@ -53,7 +53,7 @@ type ListTimelineParams = PaginationParams & WithMutedParam & OnlyEventsParam &
interface GetConversationsParams extends PaginationParams, LanguageParam {
/**
* Only return conversations with the given recipients (a list of user ids).
* Requires `features.conversationsByRecipients`.
* Requires features{@link Features['conversationsByRecipients']}.
* */
recipients?: string[];
}