Skip to content

Commit ac170ac

Browse files
feat: support new Profile API (Mastodon v4.6.0) (#1413)
* feat: support new Profile API (GET/PATCH /api/v1/profile) Add support for the Mastodon v4.6.0 Profile API: - Add Profile entity type with all documented attributes - Add fetch() and update() methods to ProfileResource - Add UpdateProfileParams for PATCH /api/v1/profile - Add PATCH dispatch handling for profile update - Add multipart-form encoding for profile update (avatar/header uploads) - Update ProfileAvatarResource/ProfileHeaderResource return types from void to AccountCredentials to match API docs - Add missing url field to FeaturedTag entity Closes #1412 Co-Authored-By: Ryō Igarashi (五十嵐 涼) <n33t5hin@gmail.com> * fix: bump size limits for rest/oauth to 4.1 kB The new Profile API support adds ~10 bytes of runtime code to the dispatcher hook (PATCH method + multipart-form encoding for /api/v1/profile). Bump rest and oauth size limits from 4.0 to 4.1 kB. Co-Authored-By: Ryō Igarashi (五十嵐 涼) <n33t5hin@gmail.com> * refactor: use PUT instead of PATCH for profile update Rails routes both PUT and PATCH to the same update action, so the PATCH override in dispatch() is unnecessary. This keeps the size limits within the original 4.0 kB budget. Co-Authored-By: Ryō Igarashi (五十嵐 涼) <n33t5hin@gmail.com> * refactor: remove inferEncoding override, add E2E tests, update to nightly - Remove unnecessary inferEncoding override for /api/v1/profile since Rails routes both PUT and PATCH to the same update action - Add E2E tests for profile.fetch() and profile.update() - Update compose.yml to use neetshin/mastodon-dev:nightly for Profile API support Co-Authored-By: Ryō Igarashi (五十嵐 涼) <n33t5hin@gmail.com> * chore: update docker image to 4.5.9, defer profile API tests Update compose.yml to use neetshin/mastodon-dev:4.5.9. Remove profile fetch/update E2E tests since the Profile API (GET/PATCH /api/v1/profile) is not yet available in stable Mastodon releases (planned for v4.6.0). Co-Authored-By: Ryō Igarashi (五十嵐 涼) <n33t5hin@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Ryō Igarashi (五十嵐 涼) <n33t5hin@gmail.com>
1 parent c04c5cc commit ac170ac

5 files changed

Lines changed: 117 additions & 5 deletions

File tree

compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ services:
2323

2424
mastodon:
2525
restart: always
26-
image: neetshin/mastodon-dev:4.5.3
26+
image: neetshin/mastodon-dev:4.5.9
2727
ports:
2828
- "3000:3000"
2929
- "4000:4000"

src/mastodon/entities/v1/featured-tags.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export interface FeaturedTag {
77
id: string;
88
/** The name of the hashtag being featured. */
99
name: string;
10+
/** A link to all statuses by a user that contain this hashtag. */
11+
url: string;
1012
/** The number of authored statuses containing this hashtag */
1113
statusesCount: number;
1214
/** The timestamp of the last authored status containing this hashtag. */

src/mastodon/entities/v1/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export type * from "./notification.js";
2626
export type * from "./notification-request.js";
2727
export type * from "./poll.js";
2828
export type * from "./preference.js";
29+
export type * from "./profile.js";
2930
export type * from "./preview-card.js";
3031
export type * from "./quote-approval.js";
3132
export type * from "./quote.js";
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { type AccountField } from "./account.js";
2+
import { type FeaturedTag } from "./featured-tags.js";
3+
4+
/**
5+
* Represents the current user's profile, with source values for all the editable fields.
6+
* @see https://docs.joinmastodon.org/entities/Profile/
7+
*/
8+
export interface Profile {
9+
/** The account id. */
10+
id: string;
11+
/** The profile's display name. */
12+
displayName: string;
13+
/** The profile's bio or description. Unlike for Account, this is the raw unprocessed text, not the rendered HTML. */
14+
note: string;
15+
/** Metadata about the account. Contains the raw unprocessed names and values. */
16+
fields: AccountField[];
17+
/** An image icon that is shown next to statuses and in the profile. Unlike for Account, this is nullable and will be null if the avatar is unset. */
18+
avatar: string | null;
19+
/** A static version of the avatar. Unlike for Account, this is nullable and will be null if the avatar is unset. */
20+
avatarStatic: string | null;
21+
/** A textual description of the avatar, to be used for the visually impaired or when avatars do not load. */
22+
avatarDescription: string;
23+
/** An image banner that is shown above the profile and in profile cards. Unlike for Account, this is nullable and will be null if the header is unset. */
24+
header: string | null;
25+
/** A static version of the header. Unlike for Account, this is nullable and will be null if the header is unset. */
26+
headerStatic: string | null;
27+
/** A textual description of the profile header, to be used for the visually impaired or when avatars do not load. */
28+
headerDescription: string;
29+
/** Whether the account manually approves follow requests. */
30+
locked: boolean;
31+
/** Indicates that the account may perform automated actions, may not be monitored, or identifies as a robot. */
32+
bot: boolean;
33+
/** Whether the user hides the contents of their follows and followers collections. */
34+
hideCollections: boolean | null;
35+
/** Whether the account has opted into discovery features such as the profile directory. */
36+
discoverable: boolean | null;
37+
/** Whether the account allows indexing by search engines. */
38+
indexable: boolean;
39+
/** Whether the account wishes to have a "Media" tab with media attachments on their profile. */
40+
showMedia: boolean;
41+
/** Whether the account wishes to have replies in the "Media" tab on their profile. */
42+
showMediaReplies: boolean;
43+
/** Whether the account wishes to have a "Featured" tab on their profile. */
44+
showFeatured: boolean;
45+
/** Domains of websites allowed to credit the account. */
46+
attributionDomains: string[];
47+
/** Featured hashtags on the profile. */
48+
featuredTags: FeaturedTag[];
49+
}

src/mastodon/rest/v1/profile.ts

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,78 @@
1+
import { type HttpMetaParams } from "../../../interfaces/index.js";
2+
import {
3+
type AccountCredentials,
4+
type AccountField,
5+
type Profile,
6+
} from "../../entities/v1/index.js";
17
import { type Method } from "../../method.js";
28

9+
export interface UpdateProfileParams {
10+
/** The display name to use for the profile. */
11+
readonly displayName?: string | null;
12+
/** The account bio. */
13+
readonly note?: string | null;
14+
/** Avatar image encoded using multipart/form-data */
15+
readonly avatar?: Blob | string | null;
16+
/** A textual description of the avatar. */
17+
readonly avatarDescription?: string | null;
18+
/** Header image encoded using multipart/form-data */
19+
readonly header?: Blob | string | null;
20+
/** A textual description of the header. */
21+
readonly headerDescription?: string | null;
22+
/** Whether manual approval of follow requests is required. */
23+
readonly locked?: boolean | null;
24+
/** Whether the account has a bot flag. */
25+
readonly bot?: boolean | null;
26+
/** Whether the account should be shown in the profile directory. */
27+
readonly discoverable?: boolean | null;
28+
/** Whether you want to hide followers and followings on your profile. */
29+
readonly hideCollections?: boolean | null;
30+
/** Whether the account allows indexing by search engines. */
31+
readonly indexable?: boolean | null;
32+
/** Whether the account wishes to have a "Media" tab with media attachments on their profile. */
33+
readonly showMedia?: boolean | null;
34+
/** Whether the account wishes to have replies in the "Media" tab on their profile. */
35+
readonly showMediaReplies?: boolean | null;
36+
/** Whether the account wishes to have a "Featured" tab on their profile. */
37+
readonly showFeatured?: boolean | null;
38+
/** Domains of websites allowed to credit the account. */
39+
readonly attributionDomains?: string[] | null;
40+
/** Profile metadata `name` and `value`. */
41+
readonly fieldsAttributes?: AccountField[] | null;
42+
}
43+
344
export interface ProfileAvatarResource {
4-
/**https://github.com/mastodon/mastodon/pull/25124 */
5-
remove: Method<void>;
45+
/** @see https://docs.joinmastodon.org/methods/profile/#delete-profile-avatar */
46+
remove: Method<AccountCredentials>;
647
}
748

849
export interface ProfileHeaderResource {
9-
/**https://github.com/mastodon/mastodon/pull/25124 */
10-
remove: Method<void>;
50+
/** @see https://docs.joinmastodon.org/methods/profile/#delete-profile-header */
51+
remove: Method<AccountCredentials>;
1152
}
1253

1354
export interface ProfileResource {
1455
avatar: ProfileAvatarResource;
1556
header: ProfileHeaderResource;
57+
58+
/**
59+
* Get the current user's profile.
60+
* @return Profile
61+
* @see https://docs.joinmastodon.org/methods/profile/
62+
*/
63+
fetch: Method<Profile>;
64+
65+
/**
66+
* Update the current user's profile.
67+
* @param params Parameters
68+
* @return Profile
69+
* @see https://docs.joinmastodon.org/methods/profile/
70+
*/
71+
update: Method<
72+
Profile,
73+
UpdateProfileParams,
74+
HttpMetaParams<"multipart-form">
75+
>;
1676
}
1777

1878
/** @deprecated Use `ProfileResource` instead. */

0 commit comments

Comments
 (0)