rettiwt-api 6.3.0-alpha.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -31
- package/dist/Rettiwt.d.ts +6 -2
- package/dist/Rettiwt.js +7 -3
- package/dist/Rettiwt.js.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/collections/Extractors.d.ts +15 -2
- package/dist/collections/Extractors.js +12 -1
- package/dist/collections/Extractors.js.map +1 -1
- package/dist/collections/Groups.js +8 -0
- package/dist/collections/Groups.js.map +1 -1
- package/dist/collections/Requests.js +8 -0
- package/dist/collections/Requests.js.map +1 -1
- package/dist/commands/Space.d.ts +10 -0
- package/dist/commands/Space.js +38 -0
- package/dist/commands/Space.js.map +1 -0
- package/dist/commands/User.js +139 -0
- package/dist/commands/User.js.map +1 -1
- package/dist/enums/Resource.d.ts +8 -1
- package/dist/enums/Resource.js +8 -0
- package/dist/enums/Resource.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/models/RettiwtConfig.d.ts +26 -3
- package/dist/models/RettiwtConfig.js +68 -3
- package/dist/models/RettiwtConfig.js.map +1 -1
- package/dist/models/args/FetchArgs.d.ts +3 -0
- package/dist/models/args/FetchArgs.js +6 -0
- package/dist/models/args/FetchArgs.js.map +1 -1
- package/dist/models/args/PostArgs.d.ts +24 -1
- package/dist/models/args/PostArgs.js +52 -1
- package/dist/models/args/PostArgs.js.map +1 -1
- package/dist/models/data/Space.d.ts +70 -0
- package/dist/models/data/Space.js +177 -0
- package/dist/models/data/Space.js.map +1 -0
- package/dist/models/data/UserAbout.d.ts +44 -0
- package/dist/models/data/UserAbout.js +129 -0
- package/dist/models/data/UserAbout.js.map +1 -0
- package/dist/requests/Space.d.ts +15 -0
- package/dist/requests/Space.js +74 -0
- package/dist/requests/Space.js.map +1 -0
- package/dist/requests/Tweet.d.ts +4 -0
- package/dist/requests/Tweet.js +57 -0
- package/dist/requests/Tweet.js.map +1 -1
- package/dist/requests/User.d.ts +21 -0
- package/dist/requests/User.js +64 -0
- package/dist/requests/User.js.map +1 -1
- package/dist/services/internal/AuthService.d.ts +25 -0
- package/dist/services/internal/AuthService.js +121 -0
- package/dist/services/internal/AuthService.js.map +1 -1
- package/dist/services/public/DirectMessageService.js +3 -3
- package/dist/services/public/DirectMessageService.js.map +1 -1
- package/dist/services/public/FetcherService.d.ts +4 -3
- package/dist/services/public/FetcherService.js +22 -16
- package/dist/services/public/FetcherService.js.map +1 -1
- package/dist/services/public/ListService.js +5 -5
- package/dist/services/public/ListService.js.map +1 -1
- package/dist/services/public/SpaceService.d.ts +42 -0
- package/dist/services/public/SpaceService.js +60 -0
- package/dist/services/public/SpaceService.js.map +1 -0
- package/dist/services/public/TweetService.js +26 -23
- package/dist/services/public/TweetService.js.map +1 -1
- package/dist/services/public/UserService.d.ts +79 -0
- package/dist/services/public/UserService.js +203 -23
- package/dist/services/public/UserService.js.map +1 -1
- package/dist/types/RettiwtConfig.d.ts +33 -3
- package/dist/types/args/FetchArgs.d.ts +35 -1
- package/dist/types/args/PostArgs.d.ts +44 -1
- package/dist/types/data/Space.d.ts +89 -0
- package/dist/types/data/Space.js +3 -0
- package/dist/types/data/Space.js.map +1 -0
- package/dist/types/data/UserAbout.d.ts +68 -0
- package/dist/types/data/UserAbout.js +3 -0
- package/dist/types/data/UserAbout.js.map +1 -0
- package/dist/types/raw/base/Space.d.ts +43 -22
- package/dist/types/raw/space/AudioSpaceById.d.ts +50 -0
- package/dist/types/raw/space/AudioSpaceById.js +4 -0
- package/dist/types/raw/space/AudioSpaceById.js.map +1 -0
- package/dist/types/raw/space/Details.d.ts +2 -309
- package/dist/types/raw/tweet/Post.d.ts +16 -1
- package/dist/types/raw/user/About.d.ts +65 -0
- package/dist/types/raw/user/About.js +4 -0
- package/dist/types/raw/user/About.js.map +1 -0
- package/dist/types/raw/user/ChangePassword.d.ts +8 -0
- package/dist/types/raw/user/ChangePassword.js +3 -0
- package/dist/types/raw/user/ChangePassword.js.map +1 -0
- package/dist/types/raw/user/ProfileUpdate.d.ts +1 -0
- package/dist/types/raw/user/Settings.d.ts +21 -0
- package/dist/types/raw/user/Settings.js +4 -0
- package/dist/types/raw/user/Settings.js.map +1 -0
- package/package.json +6 -4
- package/src/Rettiwt.ts +10 -3
- package/src/cli.ts +3 -1
- package/src/collections/Extractors.ts +22 -3
- package/src/collections/Groups.ts +8 -0
- package/src/collections/Requests.ts +11 -0
- package/src/commands/Space.ts +46 -0
- package/src/commands/User.ts +159 -0
- package/src/enums/Resource.ts +9 -0
- package/src/index.ts +11 -1
- package/src/models/RettiwtConfig.ts +81 -6
- package/src/models/args/FetchArgs.ts +6 -0
- package/src/models/args/PostArgs.ts +58 -1
- package/src/models/data/Space.ts +201 -0
- package/src/models/data/UserAbout.ts +161 -0
- package/src/requests/Space.ts +76 -0
- package/src/requests/Tweet.ts +59 -0
- package/src/requests/User.ts +69 -0
- package/src/services/internal/AuthService.ts +149 -1
- package/src/services/public/DirectMessageService.ts +3 -3
- package/src/services/public/FetcherService.ts +25 -18
- package/src/services/public/ListService.ts +5 -5
- package/src/services/public/SpaceService.ts +65 -0
- package/src/services/public/TweetService.ts +27 -24
- package/src/services/public/UserService.ts +247 -23
- package/src/types/RettiwtConfig.ts +35 -3
- package/src/types/args/FetchArgs.ts +41 -1
- package/src/types/args/PostArgs.ts +50 -1
- package/src/types/data/Space.ts +122 -0
- package/src/types/data/UserAbout.ts +87 -0
- package/src/types/raw/base/Space.ts +42 -22
- package/src/types/raw/space/AudioSpaceById.ts +57 -0
- package/src/types/raw/space/Details.ts +3 -352
- package/src/types/raw/tweet/Post.ts +19 -1
- package/src/types/raw/user/About.ts +77 -0
- package/src/types/raw/user/ChangePassword.ts +8 -0
- package/src/types/raw/user/ProfileUpdate.ts +1 -0
- package/src/types/raw/user/Settings.ts +23 -0
- package/tsconfig.json +2 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The raw data received when fetching the about profile of the given user.
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface IUserAboutResponse {
|
|
7
|
+
data: Data;
|
|
8
|
+
}
|
|
9
|
+
interface Data {
|
|
10
|
+
user_result_by_screen_name: UserResultByScreenName;
|
|
11
|
+
}
|
|
12
|
+
interface UserResultByScreenName {
|
|
13
|
+
result: IUserAboutResult;
|
|
14
|
+
id: string;
|
|
15
|
+
}
|
|
16
|
+
export interface IUserAboutResult {
|
|
17
|
+
__typename: string;
|
|
18
|
+
id: string;
|
|
19
|
+
rest_id: string;
|
|
20
|
+
avatar?: Avatar;
|
|
21
|
+
core?: Core;
|
|
22
|
+
profile_image_shape?: string;
|
|
23
|
+
verification?: Verification;
|
|
24
|
+
affiliates_highlighted_label?: unknown;
|
|
25
|
+
is_blue_verified?: boolean;
|
|
26
|
+
privacy?: Privacy;
|
|
27
|
+
about_profile?: AboutProfile;
|
|
28
|
+
verification_info?: VerificationInfo;
|
|
29
|
+
identity_profile_labels_highlighted_label?: unknown;
|
|
30
|
+
}
|
|
31
|
+
interface Avatar {
|
|
32
|
+
image_url: string;
|
|
33
|
+
}
|
|
34
|
+
interface Core {
|
|
35
|
+
created_at: string;
|
|
36
|
+
name: string;
|
|
37
|
+
screen_name: string;
|
|
38
|
+
}
|
|
39
|
+
interface Verification {
|
|
40
|
+
verified: boolean;
|
|
41
|
+
}
|
|
42
|
+
interface Privacy {
|
|
43
|
+
protected: boolean;
|
|
44
|
+
}
|
|
45
|
+
interface AboutProfile {
|
|
46
|
+
created_country_accurate?: boolean;
|
|
47
|
+
account_based_in?: string;
|
|
48
|
+
location_accurate?: boolean;
|
|
49
|
+
learn_more_url?: string;
|
|
50
|
+
source?: string;
|
|
51
|
+
username_changes?: UsernameChanges;
|
|
52
|
+
}
|
|
53
|
+
interface UsernameChanges {
|
|
54
|
+
count?: string;
|
|
55
|
+
last_changed_at_msec?: string;
|
|
56
|
+
}
|
|
57
|
+
interface VerificationInfo {
|
|
58
|
+
reason?: VerificationReason;
|
|
59
|
+
id?: string;
|
|
60
|
+
is_identity_verified?: boolean;
|
|
61
|
+
}
|
|
62
|
+
interface VerificationReason {
|
|
63
|
+
verified_since_msec?: string;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"About.js","sourceRoot":"","sources":["../../../../src/types/raw/user/About.ts"],"names":[],"mappings":";AAAA,oBAAoB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChangePassword.js","sourceRoot":"","sources":["../../../../src/types/raw/user/ChangePassword.ts"],"names":[],"mappings":""}
|
|
@@ -37,6 +37,7 @@ export interface IUserProfileUpdateResponse {
|
|
|
37
37
|
profile_image_url: string;
|
|
38
38
|
profile_image_url_https: string;
|
|
39
39
|
profile_banner_url: string;
|
|
40
|
+
profile_banner_url_https?: string;
|
|
40
41
|
profile_link_color: string;
|
|
41
42
|
profile_sidebar_border_color: string;
|
|
42
43
|
profile_sidebar_fill_color: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The raw data received from the account settings endpoint.
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface IUserSettingsResponse {
|
|
7
|
+
screen_name: string;
|
|
8
|
+
protected: boolean;
|
|
9
|
+
language: string;
|
|
10
|
+
geo_enabled: boolean;
|
|
11
|
+
discoverable_by_email: boolean;
|
|
12
|
+
discoverable_by_mobile_phone: boolean;
|
|
13
|
+
use_cookie_personalization: boolean;
|
|
14
|
+
sleep_time: {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
end_time: any;
|
|
17
|
+
start_time: any;
|
|
18
|
+
};
|
|
19
|
+
display_sensitive_media: boolean;
|
|
20
|
+
allow_media_tagging: string;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Settings.js","sourceRoot":"","sources":["../../../../src/types/raw/user/Settings.ts"],"names":[],"mappings":";AAAA,6FAA6F"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rettiwt-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"description": "An API for fetching data from TwitterAPI, without any rate limits!",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@typescript-eslint/parser": "^8.24.0",
|
|
41
41
|
"eslint": "^9.20.1",
|
|
42
42
|
"eslint-plugin-import": "^2.31.0",
|
|
43
|
-
"eslint-plugin-tsdoc": "^0.
|
|
43
|
+
"eslint-plugin-tsdoc": "^0.5.2",
|
|
44
44
|
"nodemon": "^3.1.9",
|
|
45
45
|
"prettier": "^3.5.1",
|
|
46
46
|
"typedoc": "^0.27.7",
|
|
@@ -51,9 +51,11 @@
|
|
|
51
51
|
"chalk": "^5.4.1",
|
|
52
52
|
"commander": "^11.1.0",
|
|
53
53
|
"cookiejar": "^2.1.4",
|
|
54
|
+
"http-proxy-agent": "^7.0.2",
|
|
54
55
|
"https-proxy-agent": "^7.0.6",
|
|
55
|
-
"
|
|
56
|
+
"linkedom": "^0.18.12",
|
|
56
57
|
"node-html-parser": "^7.0.1",
|
|
57
|
-
"
|
|
58
|
+
"socks-proxy-agent": "^8.0.5",
|
|
59
|
+
"x-client-transaction-id": "^0.2.0"
|
|
58
60
|
}
|
|
59
61
|
}
|
package/src/Rettiwt.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { AxiosProxyConfig } from 'axios';
|
|
2
|
+
|
|
1
3
|
import { RettiwtConfig } from './models/RettiwtConfig';
|
|
2
4
|
import { DirectMessageService } from './services/public/DirectMessageService';
|
|
3
5
|
import { ListService } from './services/public/ListService';
|
|
6
|
+
import { SpaceService } from './services/public/SpaceService';
|
|
4
7
|
import { TweetService } from './services/public/TweetService';
|
|
5
8
|
import { UserService } from './services/public/UserService';
|
|
6
9
|
import { IRettiwtConfig } from './types/RettiwtConfig';
|
|
@@ -56,6 +59,9 @@ export class Rettiwt {
|
|
|
56
59
|
/** The instance used to fetch data related to lists. */
|
|
57
60
|
public list: ListService;
|
|
58
61
|
|
|
62
|
+
/** The instance used to fetch data related to spaces. */
|
|
63
|
+
public space: SpaceService;
|
|
64
|
+
|
|
59
65
|
/** The instance used to fetch data related to tweets. */
|
|
60
66
|
public tweet: TweetService;
|
|
61
67
|
|
|
@@ -71,6 +77,7 @@ export class Rettiwt {
|
|
|
71
77
|
this._config = new RettiwtConfig(config);
|
|
72
78
|
this.dm = new DirectMessageService(this._config);
|
|
73
79
|
this.list = new ListService(this._config);
|
|
80
|
+
this.space = new SpaceService(this._config);
|
|
74
81
|
this.tweet = new TweetService(this._config);
|
|
75
82
|
this.user = new UserService(this._config);
|
|
76
83
|
}
|
|
@@ -90,8 +97,8 @@ export class Rettiwt {
|
|
|
90
97
|
this._config.headers = headers;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
|
-
/** Set the proxy
|
|
94
|
-
public set
|
|
95
|
-
this._config.
|
|
100
|
+
/** Set the proxy for the current instance. */
|
|
101
|
+
public set proxy(proxy: AxiosProxyConfig | string | undefined | null) {
|
|
102
|
+
this._config.proxy = proxy;
|
|
96
103
|
}
|
|
97
104
|
}
|
package/src/cli.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { createCommand } from 'commander';
|
|
|
4
4
|
|
|
5
5
|
import dm from './commands/DirectMessage';
|
|
6
6
|
import list from './commands/List';
|
|
7
|
+
import space from './commands/Space';
|
|
7
8
|
import tweet from './commands/Tweet';
|
|
8
9
|
import user from './commands/User';
|
|
9
10
|
import { Rettiwt } from './Rettiwt';
|
|
@@ -32,7 +33,7 @@ Program.parse();
|
|
|
32
33
|
const RettiwtInstance = new Rettiwt({
|
|
33
34
|
apiKey: process.env.API_KEY ?? (Program.opts().key as string),
|
|
34
35
|
logging: Program.opts().log ? true : false,
|
|
35
|
-
|
|
36
|
+
proxy: Program.opts().proxy as string,
|
|
36
37
|
timeout: Program.opts().timeout ? Number(Program.opts().timeout) : undefined,
|
|
37
38
|
maxRetries: Program.opts().retries as number,
|
|
38
39
|
delay: Program.opts().delay as number,
|
|
@@ -41,6 +42,7 @@ const RettiwtInstance = new Rettiwt({
|
|
|
41
42
|
// Adding sub-commands
|
|
42
43
|
Program.addCommand(dm(RettiwtInstance));
|
|
43
44
|
Program.addCommand(list(RettiwtInstance));
|
|
45
|
+
Program.addCommand(space(RettiwtInstance));
|
|
44
46
|
Program.addCommand(tweet(RettiwtInstance));
|
|
45
47
|
Program.addCommand(user(RettiwtInstance));
|
|
46
48
|
|
|
@@ -6,8 +6,10 @@ import { CursoredData } from '../models/data/CursoredData';
|
|
|
6
6
|
import { Inbox } from '../models/data/Inbox';
|
|
7
7
|
import { List } from '../models/data/List';
|
|
8
8
|
import { Notification } from '../models/data/Notification';
|
|
9
|
+
import { Space } from '../models/data/Space';
|
|
9
10
|
import { Tweet } from '../models/data/Tweet';
|
|
10
11
|
import { User } from '../models/data/User';
|
|
12
|
+
import { UserAbout } from '../models/data/UserAbout';
|
|
11
13
|
import { IConversationTimelineResponse } from '../types/raw/dm/Conversation';
|
|
12
14
|
import { IInboxInitialResponse } from '../types/raw/dm/InboxInitial';
|
|
13
15
|
import { IInboxTimelineResponse } from '../types/raw/dm/InboxTimeline';
|
|
@@ -17,12 +19,13 @@ import { IListMembersResponse } from '../types/raw/list/Members';
|
|
|
17
19
|
import { IListMemberRemoveResponse } from '../types/raw/list/RemoveMember';
|
|
18
20
|
import { IListTweetsResponse } from '../types/raw/list/Tweets';
|
|
19
21
|
import { IMediaInitializeUploadResponse } from '../types/raw/media/InitalizeUpload';
|
|
22
|
+
import { IAudioSpaceByIdResponse } from '../types/raw/space/AudioSpaceById';
|
|
20
23
|
import { ITweetBookmarkResponse } from '../types/raw/tweet/Bookmark';
|
|
21
24
|
import { ITweetDetailsResponse } from '../types/raw/tweet/Details';
|
|
22
25
|
import { ITweetDetailsBulkResponse } from '../types/raw/tweet/DetailsBulk';
|
|
23
26
|
import { ITweetLikeResponse } from '../types/raw/tweet/Like';
|
|
24
27
|
import { ITweetLikersResponse } from '../types/raw/tweet/Likers';
|
|
25
|
-
import { ITweetPostResponse } from '../types/raw/tweet/Post';
|
|
28
|
+
import { ITweetPostNoteResponse, ITweetPostResponse } from '../types/raw/tweet/Post';
|
|
26
29
|
import { ITweetRepliesResponse } from '../types/raw/tweet/Replies';
|
|
27
30
|
import { ITweetRetweetResponse } from '../types/raw/tweet/Retweet';
|
|
28
31
|
import { ITweetRetweetersResponse } from '../types/raw/tweet/Retweeters';
|
|
@@ -33,11 +36,13 @@ import { ITweetUnlikeResponse } from '../types/raw/tweet/Unlike';
|
|
|
33
36
|
import { ITweetUnpostResponse } from '../types/raw/tweet/Unpost';
|
|
34
37
|
import { ITweetUnretweetResponse } from '../types/raw/tweet/Unretweet';
|
|
35
38
|
import { ITweetUnscheduleResponse } from '../types/raw/tweet/Unschedule';
|
|
39
|
+
import { IUserAboutResponse } from '../types/raw/user/About';
|
|
36
40
|
import { IUserAffiliatesResponse } from '../types/raw/user/Affiliates';
|
|
37
41
|
import { IUserAnalyticsResponse } from '../types/raw/user/Analytics';
|
|
38
42
|
import { IUserBookmarkFoldersResponse } from '../types/raw/user/BookmarkFolders';
|
|
39
43
|
import { IUserBookmarkFolderTweetsResponse } from '../types/raw/user/BookmarkFolderTweets';
|
|
40
44
|
import { IUserBookmarksResponse } from '../types/raw/user/Bookmarks';
|
|
45
|
+
import { IUserChangePasswordResponse } from '../types/raw/user/ChangePassword';
|
|
41
46
|
import { IUserDetailsResponse } from '../types/raw/user/Details';
|
|
42
47
|
import { IUserDetailsBulkResponse } from '../types/raw/user/DetailsBulk';
|
|
43
48
|
import { IUserFollowResponse } from '../types/raw/user/Follow';
|
|
@@ -52,6 +57,7 @@ import { IUserNotificationsResponse } from '../types/raw/user/Notifications';
|
|
|
52
57
|
import { IUserProfileUpdateResponse } from '../types/raw/user/ProfileUpdate';
|
|
53
58
|
import { IUserRecommendedResponse } from '../types/raw/user/Recommended';
|
|
54
59
|
import { IUserSearchResponse } from '../types/raw/user/Search';
|
|
60
|
+
import { IUserSettingsResponse } from '../types/raw/user/Settings';
|
|
55
61
|
import { IUserSubscriptionsResponse } from '../types/raw/user/Subscriptions';
|
|
56
62
|
import { IUserTweetsResponse } from '../types/raw/user/Tweets';
|
|
57
63
|
import { IUserTweetsAndRepliesResponse } from '../types/raw/user/TweetsAndReplies';
|
|
@@ -85,6 +91,8 @@ export const Extractors = {
|
|
|
85
91
|
DM_INBOX_INITIAL_STATE: (response: IInboxInitialResponse): Inbox => new Inbox(response),
|
|
86
92
|
DM_INBOX_TIMELINE: (response: IInboxTimelineResponse): Inbox => new Inbox(response),
|
|
87
93
|
|
|
94
|
+
SPACE_DETAILS: (response: IAudioSpaceByIdResponse): Space | undefined => Space.single(response),
|
|
95
|
+
|
|
88
96
|
TWEET_BOOKMARK: (response: ITweetBookmarkResponse): boolean => response?.data?.tweet_bookmark_put === 'Done',
|
|
89
97
|
TWEET_DETAILS: (response: ITweetDetailsResponse, id: string): Tweet | undefined => Tweet.single(response, id),
|
|
90
98
|
TWEET_DETAILS_ALT: (response: ITweetRepliesResponse, id: string): Tweet | undefined => Tweet.single(response, id),
|
|
@@ -92,8 +100,12 @@ export const Extractors = {
|
|
|
92
100
|
TWEET_LIKE: (response: ITweetLikeResponse): boolean => (response?.data?.favorite_tweet ? true : false),
|
|
93
101
|
TWEET_LIKERS: (response: ITweetLikersResponse): CursoredData<User> =>
|
|
94
102
|
new CursoredData<User>(response, BaseType.USER),
|
|
95
|
-
TWEET_POST: (response: ITweetPostResponse): string =>
|
|
96
|
-
response?.data?.create_tweet?.tweet_results?.result?.rest_id ??
|
|
103
|
+
TWEET_POST: (response: ITweetPostResponse): string | undefined =>
|
|
104
|
+
response?.data?.create_tweet?.tweet_results?.result?.rest_id ??
|
|
105
|
+
response?.data?.create_note_tweet?.tweet_results?.result?.rest_id ??
|
|
106
|
+
undefined,
|
|
107
|
+
TWEET_POST_NOTE: (response: ITweetPostNoteResponse): string | undefined =>
|
|
108
|
+
response?.data?.notetweet_create?.tweet_results?.result?.rest_id ?? undefined,
|
|
97
109
|
TWEET_REPLIES: (response: ITweetDetailsResponse): CursoredData<Tweet> =>
|
|
98
110
|
new CursoredData<Tweet>(response, BaseType.TWEET),
|
|
99
111
|
TWEET_RETWEET: (response: ITweetRetweetResponse): boolean => (response?.data?.create_retweet ? true : false),
|
|
@@ -119,6 +131,7 @@ export const Extractors = {
|
|
|
119
131
|
new CursoredData<BookmarkFolder>(response, BaseType.BOOKMARK_FOLDER),
|
|
120
132
|
USER_BOOKMARK_FOLDER_TWEETS: (response: IUserBookmarkFolderTweetsResponse): CursoredData<Tweet> =>
|
|
121
133
|
new CursoredData<Tweet>(response, BaseType.TWEET),
|
|
134
|
+
USER_ABOUT_BY_USERNAME: (response: IUserAboutResponse): UserAbout | undefined => UserAbout.single(response),
|
|
122
135
|
USER_DETAILS_BY_USERNAME: (response: IUserDetailsResponse): User | undefined => User.single(response),
|
|
123
136
|
USER_DETAILS_BY_ID: (response: IUserDetailsResponse): User | undefined => User.single(response),
|
|
124
137
|
USER_DETAILS_BY_IDS_BULK: (response: IUserDetailsBulkResponse, ids: string[]): User[] =>
|
|
@@ -150,6 +163,12 @@ export const Extractors = {
|
|
|
150
163
|
new CursoredData<Tweet>(response, BaseType.TWEET),
|
|
151
164
|
USER_UNFOLLOW: (response: IUserUnfollowResponse): boolean => (response?.id ? true : false),
|
|
152
165
|
USER_PROFILE_UPDATE: (response: IUserProfileUpdateResponse): boolean => (response?.name ? true : false),
|
|
166
|
+
USER_PROFILE_IMAGE_UPDATE: (response: IUserProfileUpdateResponse): boolean =>
|
|
167
|
+
response?.profile_image_url || response?.profile_image_url_https ? true : false,
|
|
168
|
+
USER_PROFILE_BANNER_UPDATE: (response: IUserProfileUpdateResponse): boolean =>
|
|
169
|
+
!response || response?.profile_banner_url || response?.profile_banner_url_https ? true : false,
|
|
170
|
+
USER_USERNAME_CHANGE: (response: IUserSettingsResponse): string | undefined => response?.screen_name ?? undefined,
|
|
171
|
+
USER_PASSWORD_CHANGE: (response: IUserChangePasswordResponse): boolean => response?.status === 'ok',
|
|
153
172
|
|
|
154
173
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
155
174
|
};
|
|
@@ -9,6 +9,7 @@ export const AllowGuestAuthenticationGroup = [
|
|
|
9
9
|
ResourceType.TWEET_DETAILS,
|
|
10
10
|
ResourceType.USER_DETAILS_BY_USERNAME,
|
|
11
11
|
ResourceType.USER_TIMELINE,
|
|
12
|
+
ResourceType.SPACE_DETAILS,
|
|
12
13
|
];
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -23,6 +24,7 @@ export const FetchResourcesGroup = [
|
|
|
23
24
|
ResourceType.DM_CONVERSATION,
|
|
24
25
|
ResourceType.DM_INBOX_INITIAL_STATE,
|
|
25
26
|
ResourceType.DM_INBOX_TIMELINE,
|
|
27
|
+
ResourceType.SPACE_DETAILS,
|
|
26
28
|
ResourceType.TWEET_DETAILS,
|
|
27
29
|
ResourceType.TWEET_DETAILS_ALT,
|
|
28
30
|
ResourceType.TWEET_DETAILS_BULK,
|
|
@@ -35,6 +37,7 @@ export const FetchResourcesGroup = [
|
|
|
35
37
|
ResourceType.USER_BOOKMARKS,
|
|
36
38
|
ResourceType.USER_BOOKMARK_FOLDERS,
|
|
37
39
|
ResourceType.USER_BOOKMARK_FOLDER_TWEETS,
|
|
40
|
+
ResourceType.USER_ABOUT_BY_USERNAME,
|
|
38
41
|
ResourceType.USER_DETAILS_BY_USERNAME,
|
|
39
42
|
ResourceType.USER_DETAILS_BY_ID,
|
|
40
43
|
ResourceType.USER_DETAILS_BY_IDS_BULK,
|
|
@@ -68,6 +71,7 @@ export const PostResourcesGroup = [
|
|
|
68
71
|
ResourceType.TWEET_BOOKMARK,
|
|
69
72
|
ResourceType.TWEET_LIKE,
|
|
70
73
|
ResourceType.TWEET_POST,
|
|
74
|
+
ResourceType.TWEET_POST_NOTE,
|
|
71
75
|
ResourceType.TWEET_RETWEET,
|
|
72
76
|
ResourceType.TWEET_SCHEDULE,
|
|
73
77
|
ResourceType.TWEET_UNBOOKMARK,
|
|
@@ -78,4 +82,8 @@ export const PostResourcesGroup = [
|
|
|
78
82
|
ResourceType.USER_FOLLOW,
|
|
79
83
|
ResourceType.USER_UNFOLLOW,
|
|
80
84
|
ResourceType.USER_PROFILE_UPDATE,
|
|
85
|
+
ResourceType.USER_PROFILE_IMAGE_UPDATE,
|
|
86
|
+
ResourceType.USER_PROFILE_BANNER_UPDATE,
|
|
87
|
+
ResourceType.USER_USERNAME_CHANGE,
|
|
88
|
+
ResourceType.USER_PASSWORD_CHANGE,
|
|
81
89
|
];
|
|
@@ -4,6 +4,7 @@ import { ResourceType } from '../enums/Resource';
|
|
|
4
4
|
import { DMRequests } from '../requests/DirectMessage';
|
|
5
5
|
import { ListRequests } from '../requests/List';
|
|
6
6
|
import { MediaRequests } from '../requests/Media';
|
|
7
|
+
import { SpaceRequests } from '../requests/Space';
|
|
7
8
|
import { TweetRequests } from '../requests/Tweet';
|
|
8
9
|
import { UserRequests } from '../requests/User';
|
|
9
10
|
import { IFetchArgs } from '../types/args/FetchArgs';
|
|
@@ -34,6 +35,9 @@ export const Requests: { [key in keyof typeof ResourceType]: (args: IFetchArgs |
|
|
|
34
35
|
DM_INBOX_TIMELINE: (args: IFetchArgs) => DMRequests.inboxTimeline(args.maxId),
|
|
35
36
|
DM_DELETE_CONVERSATION: (args: IPostArgs) => DMRequests.deleteConversation(args.conversationId!),
|
|
36
37
|
|
|
38
|
+
SPACE_DETAILS: (args: IFetchArgs) =>
|
|
39
|
+
SpaceRequests.details(args.id!, args.withReplays, args.withListeners, args.isMetatagsQuery),
|
|
40
|
+
|
|
37
41
|
TWEET_BOOKMARK: (args: IPostArgs) => TweetRequests.bookmark(args.id!),
|
|
38
42
|
TWEET_DETAILS: (args: IFetchArgs) => TweetRequests.details(args.id!),
|
|
39
43
|
TWEET_DETAILS_ALT: (args: IFetchArgs) => TweetRequests.replies(args.id!),
|
|
@@ -41,6 +45,7 @@ export const Requests: { [key in keyof typeof ResourceType]: (args: IFetchArgs |
|
|
|
41
45
|
TWEET_LIKE: (args: IPostArgs) => TweetRequests.like(args.id!),
|
|
42
46
|
TWEET_LIKERS: (args: IFetchArgs) => TweetRequests.likers(args.id!, args.count, args.cursor),
|
|
43
47
|
TWEET_POST: (args: IPostArgs) => TweetRequests.post(args.tweet!),
|
|
48
|
+
TWEET_POST_NOTE: (args: IPostArgs) => TweetRequests.postNote(args.tweet!),
|
|
44
49
|
TWEET_REPLIES: (args: IFetchArgs) =>
|
|
45
50
|
TweetRequests.replies(args.id!, args.cursor, args.sortBy ? TweetRepliesSortTypeMap[args.sortBy] : undefined),
|
|
46
51
|
TWEET_RETWEET: (args: IPostArgs) => TweetRequests.retweet(args.id!),
|
|
@@ -66,6 +71,7 @@ export const Requests: { [key in keyof typeof ResourceType]: (args: IFetchArgs |
|
|
|
66
71
|
USER_BOOKMARK_FOLDERS: (args: IFetchArgs) => UserRequests.bookmarkFolders(args.cursor),
|
|
67
72
|
USER_BOOKMARK_FOLDER_TWEETS: (args: IFetchArgs) =>
|
|
68
73
|
UserRequests.bookmarkFolderTweets(args.id!, args.count, args.cursor),
|
|
74
|
+
USER_ABOUT_BY_USERNAME: (args: IFetchArgs) => UserRequests.aboutByUsername(args.id!),
|
|
69
75
|
USER_DETAILS_BY_USERNAME: (args: IFetchArgs) => UserRequests.detailsByUsername(args.id!),
|
|
70
76
|
USER_DETAILS_BY_ID: (args: IFetchArgs) => UserRequests.detailsById(args.id!),
|
|
71
77
|
USER_DETAILS_BY_IDS_BULK: (args: IFetchArgs) => UserRequests.bulkDetailsByIds(args.ids!),
|
|
@@ -85,6 +91,11 @@ export const Requests: { [key in keyof typeof ResourceType]: (args: IFetchArgs |
|
|
|
85
91
|
USER_TIMELINE_AND_REPLIES: (args: IFetchArgs) => UserRequests.tweetsAndReplies(args.id!, args.count, args.cursor),
|
|
86
92
|
USER_UNFOLLOW: (args: IPostArgs) => UserRequests.unfollow(args.id!),
|
|
87
93
|
USER_PROFILE_UPDATE: (args: IPostArgs) => UserRequests.updateProfile(args.profileOptions!),
|
|
94
|
+
USER_PROFILE_IMAGE_UPDATE: (args: IPostArgs) => UserRequests.updateProfileImage(args.profileImage!),
|
|
95
|
+
USER_PROFILE_BANNER_UPDATE: (args: IPostArgs) => UserRequests.updateProfileBanner(args.profileBanner!),
|
|
96
|
+
USER_USERNAME_CHANGE: (args: IPostArgs) => UserRequests.changeUsername(args.username!),
|
|
97
|
+
USER_PASSWORD_CHANGE: (args: IPostArgs) =>
|
|
98
|
+
UserRequests.changePassword(args.changePassword!.currentPassword, args.changePassword!.newPassword),
|
|
88
99
|
|
|
89
100
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
90
101
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Command, createCommand } from 'commander';
|
|
2
|
+
|
|
3
|
+
import { output } from '../helper/CliUtils';
|
|
4
|
+
import { Rettiwt } from '../Rettiwt';
|
|
5
|
+
|
|
6
|
+
interface ISpaceDetailsOptions {
|
|
7
|
+
withReplays?: boolean;
|
|
8
|
+
withListeners?: boolean;
|
|
9
|
+
metatags?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new 'space' command which uses the given Rettiwt instance.
|
|
14
|
+
*
|
|
15
|
+
* @param rettiwt - The Rettiwt instance to use.
|
|
16
|
+
* @returns The created 'space' command.
|
|
17
|
+
*/
|
|
18
|
+
function createSpaceCommand(rettiwt: Rettiwt): Command {
|
|
19
|
+
// Creating the 'space' command
|
|
20
|
+
const space = createCommand('space').description('Access resources related to spaces');
|
|
21
|
+
|
|
22
|
+
// Details
|
|
23
|
+
space
|
|
24
|
+
.command('details')
|
|
25
|
+
.description('Fetch the details of a space with the given id')
|
|
26
|
+
.argument('<id>', 'The id of the space')
|
|
27
|
+
.option('--with-replays', 'Include replay information')
|
|
28
|
+
.option('--with-listeners', 'Include listeners information')
|
|
29
|
+
.option('--metatags', 'Request metatags in the response')
|
|
30
|
+
.action(async (id: string, options?: ISpaceDetailsOptions) => {
|
|
31
|
+
try {
|
|
32
|
+
const details = await rettiwt.space.details(id, {
|
|
33
|
+
withReplays: options?.withReplays,
|
|
34
|
+
withListeners: options?.withListeners,
|
|
35
|
+
isMetatagsQuery: options?.metatags,
|
|
36
|
+
});
|
|
37
|
+
output(details);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
output(error);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return space;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default createSpaceCommand;
|
package/src/commands/User.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { createInterface } from 'readline/promises';
|
|
3
|
+
import { Writable } from 'stream';
|
|
4
|
+
|
|
1
5
|
import { Command, createCommand } from 'commander';
|
|
2
6
|
|
|
3
7
|
import { RawAnalyticsGranularity, RawAnalyticsMetric } from '../enums/raw/Analytics';
|
|
@@ -110,6 +114,19 @@ function createUserCommand(rettiwt: Rettiwt): Command {
|
|
|
110
114
|
}
|
|
111
115
|
});
|
|
112
116
|
|
|
117
|
+
// About
|
|
118
|
+
user.command('about')
|
|
119
|
+
.description('Fetch the about profile of the user with the given username')
|
|
120
|
+
.argument('<username>', 'The username of the user')
|
|
121
|
+
.action(async (username: string) => {
|
|
122
|
+
try {
|
|
123
|
+
const about = await rettiwt.user.about(username);
|
|
124
|
+
output(about);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
output(error);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
113
130
|
// Details
|
|
114
131
|
user.command('details')
|
|
115
132
|
.description('Fetch the details of the user with the given id/username')
|
|
@@ -340,9 +357,144 @@ function createUserCommand(rettiwt: Rettiwt): Command {
|
|
|
340
357
|
}
|
|
341
358
|
});
|
|
342
359
|
|
|
360
|
+
// Change Password
|
|
361
|
+
user.command('change-password')
|
|
362
|
+
.description('Change your account password')
|
|
363
|
+
.option('--show-new-key', 'Include rotated apiKey in the output')
|
|
364
|
+
.action(async (options?: UserPasswordChangeOptions) => {
|
|
365
|
+
try {
|
|
366
|
+
const initialApiKey = rettiwt.apiKey;
|
|
367
|
+
const currentPassword = await promptHidden('Current password: ');
|
|
368
|
+
const newPassword = await promptHidden('New password: ');
|
|
369
|
+
const confirmPassword = await promptHidden('Confirm new password: ');
|
|
370
|
+
|
|
371
|
+
if (newPassword !== confirmPassword) {
|
|
372
|
+
throw new Error('New password confirmation does not match');
|
|
373
|
+
}
|
|
374
|
+
if (newPassword === currentPassword) {
|
|
375
|
+
throw new Error('New password must be different from current password');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const result = await rettiwt.user.changePassword(currentPassword, newPassword);
|
|
379
|
+
const apiKeyUpdated = initialApiKey !== rettiwt.apiKey;
|
|
380
|
+
const response = {
|
|
381
|
+
success: result,
|
|
382
|
+
apiKeyUpdated: result ? apiKeyUpdated : false,
|
|
383
|
+
...(options?.showNewKey ? { apiKey: rettiwt.apiKey } : {}),
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
output(response);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
output(error);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Change Username
|
|
393
|
+
user.command('change-username')
|
|
394
|
+
.description('Change your username')
|
|
395
|
+
.argument('<username>', 'The new username (with or without @)')
|
|
396
|
+
.action(async (username: string) => {
|
|
397
|
+
try {
|
|
398
|
+
const result = await rettiwt.user.changeUsername(username);
|
|
399
|
+
output(result);
|
|
400
|
+
} catch (error) {
|
|
401
|
+
output(error);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Update Profile Banner
|
|
406
|
+
user.command('update-profile-banner')
|
|
407
|
+
.description('Update your profile banner from an image file path')
|
|
408
|
+
.argument('<path>', 'The path to the banner image file')
|
|
409
|
+
.action(async (path: string) => {
|
|
410
|
+
try {
|
|
411
|
+
const result = await rettiwt.user.updateProfileBanner(fileToBase64(path));
|
|
412
|
+
output(result);
|
|
413
|
+
} catch (error) {
|
|
414
|
+
output(error);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Update Profile Image
|
|
419
|
+
user.command('update-profile-image')
|
|
420
|
+
.description('Update your profile image from an image file path')
|
|
421
|
+
.argument('<path>', 'The path to the profile image file')
|
|
422
|
+
.action(async (path: string) => {
|
|
423
|
+
try {
|
|
424
|
+
const result = await rettiwt.user.updateProfileImage(fileToBase64(path));
|
|
425
|
+
output(result);
|
|
426
|
+
} catch (error) {
|
|
427
|
+
output(error);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
|
|
343
431
|
return user;
|
|
344
432
|
}
|
|
345
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Reads a file and returns its base64 representation.
|
|
436
|
+
*
|
|
437
|
+
* @param path - The path to the file.
|
|
438
|
+
* @returns The base64 representation of the file contents.
|
|
439
|
+
*/
|
|
440
|
+
function fileToBase64(path: string): string {
|
|
441
|
+
if (path.trim().length === 0) {
|
|
442
|
+
throw new Error('File path cannot be empty');
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
return readFileSync(path).toString('base64');
|
|
447
|
+
} catch (error) {
|
|
448
|
+
if (error instanceof Error) {
|
|
449
|
+
throw new Error(`Could not read file at '${path}': ${error.message}`);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
throw new Error(`Could not read file at '${path}'`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Prompts user for hidden input without echoing typed characters.
|
|
458
|
+
*
|
|
459
|
+
* @param query - The prompt text.
|
|
460
|
+
* @returns The provided value.
|
|
461
|
+
*/
|
|
462
|
+
async function promptHidden(query: string): Promise<string> {
|
|
463
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
464
|
+
throw new Error('Password prompt requires an interactive terminal');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
let queryShown = false;
|
|
468
|
+
|
|
469
|
+
const mutedOutput = new Writable({
|
|
470
|
+
write(chunk: Buffer | string, encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
|
|
471
|
+
const text = chunk.toString();
|
|
472
|
+
|
|
473
|
+
if (!queryShown) {
|
|
474
|
+
process.stdout.write(text);
|
|
475
|
+
queryShown = text.includes(query);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
callback();
|
|
479
|
+
},
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const input = createInterface({
|
|
483
|
+
input: process.stdin,
|
|
484
|
+
output: mutedOutput,
|
|
485
|
+
terminal: true,
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
const value = await input.question(query);
|
|
490
|
+
process.stdout.write('\n');
|
|
491
|
+
|
|
492
|
+
return value;
|
|
493
|
+
} finally {
|
|
494
|
+
input.close();
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
346
498
|
/**
|
|
347
499
|
* The options for fetching user analytics.
|
|
348
500
|
*/
|
|
@@ -364,4 +516,11 @@ type UserProfileUpdateOptions = {
|
|
|
364
516
|
description?: string;
|
|
365
517
|
};
|
|
366
518
|
|
|
519
|
+
/**
|
|
520
|
+
* The options for changing account password.
|
|
521
|
+
*/
|
|
522
|
+
type UserPasswordChangeOptions = {
|
|
523
|
+
showNewKey?: boolean;
|
|
524
|
+
};
|
|
525
|
+
|
|
367
526
|
export default createUserCommand;
|
package/src/enums/Resource.ts
CHANGED
|
@@ -22,6 +22,9 @@ export enum ResourceType {
|
|
|
22
22
|
DM_INBOX_TIMELINE = 'DM_INBOX_TIMELINE',
|
|
23
23
|
DM_DELETE_CONVERSATION = 'DM_DELETE_CONVERSATION',
|
|
24
24
|
|
|
25
|
+
// SPACE
|
|
26
|
+
SPACE_DETAILS = 'SPACE_DETAILS',
|
|
27
|
+
|
|
25
28
|
// TWEET
|
|
26
29
|
TWEET_BOOKMARK = 'TWEET_BOOKMARK',
|
|
27
30
|
TWEET_DETAILS = 'TWEET_DETAILS',
|
|
@@ -30,6 +33,7 @@ export enum ResourceType {
|
|
|
30
33
|
TWEET_LIKE = 'TWEET_LIKE',
|
|
31
34
|
TWEET_LIKERS = 'TWEET_LIKERS',
|
|
32
35
|
TWEET_POST = 'TWEET_POST',
|
|
36
|
+
TWEET_POST_NOTE = 'TWEET_POST_NOTE',
|
|
33
37
|
TWEET_REPLIES = 'TWEET_REPLIES',
|
|
34
38
|
TWEET_RETWEET = 'TWEET_RETWEET',
|
|
35
39
|
TWEET_RETWEETERS = 'TWEET_RETWEETERS',
|
|
@@ -47,6 +51,7 @@ export enum ResourceType {
|
|
|
47
51
|
USER_BOOKMARKS = 'USER_BOOKMARKS',
|
|
48
52
|
USER_BOOKMARK_FOLDERS = 'USER_BOOKMARK_FOLDERS',
|
|
49
53
|
USER_BOOKMARK_FOLDER_TWEETS = 'USER_BOOKMARK_FOLDER_TWEETS',
|
|
54
|
+
USER_ABOUT_BY_USERNAME = 'USER_ABOUT_BY_USERNAME',
|
|
50
55
|
USER_DETAILS_BY_USERNAME = 'USER_DETAILS_BY_USERNAME',
|
|
51
56
|
USER_DETAILS_BY_ID = 'USER_DETAILS_BY_ID',
|
|
52
57
|
USER_DETAILS_BY_IDS_BULK = 'USER_DETAILS_BY_IDS_BULK',
|
|
@@ -66,4 +71,8 @@ export enum ResourceType {
|
|
|
66
71
|
USER_TIMELINE_AND_REPLIES = 'USER_TIMELINE_AND_REPLIES',
|
|
67
72
|
USER_UNFOLLOW = 'USER_UNFOLLOW',
|
|
68
73
|
USER_PROFILE_UPDATE = 'USER_PROFILE_UPDATE',
|
|
74
|
+
USER_PROFILE_IMAGE_UPDATE = 'USER_PROFILE_IMAGE_UPDATE',
|
|
75
|
+
USER_PROFILE_BANNER_UPDATE = 'USER_PROFILE_BANNER_UPDATE',
|
|
76
|
+
USER_USERNAME_CHANGE = 'USER_USERNAME_CHANGE',
|
|
77
|
+
USER_PASSWORD_CHANGE = 'USER_PASSWORD_CHANGE',
|
|
69
78
|
}
|