rettiwt-api 1.3.1 → 2.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/.eslintignore +3 -0
- package/.eslintrc.js +54 -0
- package/.github/workflows/documentation.yml +47 -0
- package/.github/workflows/{publish-to-npm.yml → publish.yml} +8 -8
- package/.prettierignore +3 -0
- package/.prettierrc +13 -0
- package/README.md +59 -61
- package/dist/Rettiwt.d.ts +19 -0
- package/dist/Rettiwt.js +30 -0
- package/dist/Rettiwt.js.map +1 -0
- package/dist/enums/ApiErrors.d.ts +30 -0
- package/dist/enums/ApiErrors.js +35 -0
- package/dist/enums/ApiErrors.js.map +1 -0
- package/dist/enums/HTTP.d.ts +11 -11
- package/dist/enums/HTTP.js +15 -16
- package/dist/enums/HTTP.js.map +1 -1
- package/dist/helper/JsonUtils.d.ts +26 -0
- package/dist/helper/JsonUtils.js +88 -0
- package/dist/helper/JsonUtils.js.map +1 -0
- package/dist/index.d.ts +10 -43
- package/dist/index.js +16 -55
- package/dist/index.js.map +1 -1
- package/dist/models/CursoredData.d.ts +37 -0
- package/dist/models/CursoredData.js +59 -0
- package/dist/models/CursoredData.js.map +1 -0
- package/dist/models/{data/Tweet.d.ts → Tweet.d.ts} +4 -4
- package/dist/models/{data/Tweet.js → Tweet.js} +7 -32
- package/dist/models/Tweet.js.map +1 -0
- package/dist/models/{data/User.d.ts → User.d.ts} +3 -3
- package/dist/models/{data/User.js → User.js} +3 -3
- package/dist/models/User.js.map +1 -0
- package/dist/services/FetcherService.d.ts +66 -0
- package/dist/services/FetcherService.js +207 -0
- package/dist/services/FetcherService.js.map +1 -0
- package/dist/services/TweetService.d.ts +88 -0
- package/dist/services/TweetService.js +244 -0
- package/dist/services/TweetService.js.map +1 -0
- package/dist/services/UserService.d.ts +60 -0
- package/dist/services/UserService.js +188 -0
- package/dist/services/UserService.js.map +1 -0
- package/dist/types/{Service.d.ts → CursoredData.d.ts} +3 -3
- package/dist/types/CursoredData.js +3 -0
- package/dist/types/CursoredData.js.map +1 -0
- package/dist/types/Tweet.js +1 -1
- package/dist/types/User.js +1 -1
- package/package.json +15 -19
- package/src/Rettiwt.ts +33 -0
- package/src/enums/ApiErrors.ts +30 -0
- package/src/enums/HTTP.ts +12 -12
- package/src/helper/JsonUtils.ts +86 -0
- package/src/index.ts +14 -57
- package/src/models/CursoredData.ts +64 -0
- package/src/models/Tweet.ts +116 -0
- package/src/models/User.ts +72 -0
- package/src/services/FetcherService.ts +183 -0
- package/src/services/TweetService.ts +153 -0
- package/src/services/UserService.ts +117 -0
- package/src/types/CursoredData.ts +24 -0
- package/src/types/Tweet.ts +35 -35
- package/src/types/User.ts +30 -30
- package/tsconfig.json +9 -9
- package/.github/workflows/build-docs.yml +0 -28
- package/dist/config/env.d.ts +0 -5
- package/dist/config/env.js +0 -9
- package/dist/config/env.js.map +0 -1
- package/dist/enums/Errors.d.ts +0 -21
- package/dist/enums/Errors.js +0 -29
- package/dist/enums/Errors.js.map +0 -1
- package/dist/graphql/enums/Errors.d.ts +0 -21
- package/dist/graphql/enums/Errors.js +0 -29
- package/dist/graphql/enums/Errors.js.map +0 -1
- package/dist/graphql/queries/RootQuery.d.ts +0 -4
- package/dist/graphql/queries/RootQuery.js +0 -78
- package/dist/graphql/queries/RootQuery.js.map +0 -1
- package/dist/graphql/resolvers/AccountResolver.d.ts +0 -12
- package/dist/graphql/resolvers/AccountResolver.js +0 -84
- package/dist/graphql/resolvers/AccountResolver.js.map +0 -1
- package/dist/graphql/resolvers/ResolverBase.d.ts +0 -16
- package/dist/graphql/resolvers/ResolverBase.js +0 -23
- package/dist/graphql/resolvers/ResolverBase.js.map +0 -1
- package/dist/graphql/resolvers/TweetResolver.d.ts +0 -46
- package/dist/graphql/resolvers/TweetResolver.js +0 -312
- package/dist/graphql/resolvers/TweetResolver.js.map +0 -1
- package/dist/graphql/resolvers/UserResolver.d.ts +0 -48
- package/dist/graphql/resolvers/UserResolver.js +0 -334
- package/dist/graphql/resolvers/UserResolver.js.map +0 -1
- package/dist/graphql/types/Global.d.ts +0 -4
- package/dist/graphql/types/Global.js +0 -13
- package/dist/graphql/types/Global.js.map +0 -1
- package/dist/graphql/types/TweetTypes.d.ts +0 -4
- package/dist/graphql/types/TweetTypes.js +0 -160
- package/dist/graphql/types/TweetTypes.js.map +0 -1
- package/dist/graphql/types/UserTypes.d.ts +0 -3
- package/dist/graphql/types/UserTypes.js +0 -137
- package/dist/graphql/types/UserTypes.js.map +0 -1
- package/dist/models/args/TweetListArgs.d.ts +0 -21
- package/dist/models/args/TweetListArgs.js +0 -54
- package/dist/models/args/TweetListArgs.js.map +0 -1
- package/dist/models/args/UserListArgs.d.ts +0 -21
- package/dist/models/args/UserListArgs.js +0 -54
- package/dist/models/args/UserListArgs.js.map +0 -1
- package/dist/models/auth/AuthCookie.d.ts +0 -21
- package/dist/models/auth/AuthCookie.js +0 -33
- package/dist/models/auth/AuthCookie.js.map +0 -1
- package/dist/models/data/CursoredData.d.ts +0 -34
- package/dist/models/data/CursoredData.js +0 -42
- package/dist/models/data/CursoredData.js.map +0 -1
- package/dist/models/data/Tweet.js.map +0 -1
- package/dist/models/data/User.js.map +0 -1
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -76
- package/dist/server.js.map +0 -1
- package/dist/services/auth/AccountService.d.ts +0 -83
- package/dist/services/auth/AccountService.js +0 -412
- package/dist/services/auth/AccountService.js.map +0 -1
- package/dist/services/auth/AuthService.d.ts +0 -31
- package/dist/services/auth/AuthService.js +0 -118
- package/dist/services/auth/AuthService.js.map +0 -1
- package/dist/services/data/TweetService.d.ts +0 -60
- package/dist/services/data/TweetService.js +0 -251
- package/dist/services/data/TweetService.js.map +0 -1
- package/dist/services/data/UserService.d.ts +0 -71
- package/dist/services/data/UserService.js +0 -278
- package/dist/services/data/UserService.js.map +0 -1
- package/dist/services/helper/Headers.d.ts +0 -19
- package/dist/services/helper/Headers.js +0 -62
- package/dist/services/helper/Headers.js.map +0 -1
- package/dist/services/helper/Parser.d.ts +0 -22
- package/dist/services/helper/Parser.js +0 -84
- package/dist/services/helper/Parser.js.map +0 -1
- package/dist/services/helper/extractors/Tweets.d.ts +0 -23
- package/dist/services/helper/extractors/Tweets.js +0 -200
- package/dist/services/helper/extractors/Tweets.js.map +0 -1
- package/dist/services/helper/extractors/Users.d.ts +0 -17
- package/dist/services/helper/extractors/Users.js +0 -151
- package/dist/services/helper/extractors/Users.js.map +0 -1
- package/dist/services/helper/payloads/LoginFlows.d.ts +0 -77
- package/dist/services/helper/payloads/LoginFlows.js +0 -92
- package/dist/services/helper/payloads/LoginFlows.js.map +0 -1
- package/dist/services/helper/urls/Authentication.d.ts +0 -4
- package/dist/services/helper/urls/Authentication.js +0 -11
- package/dist/services/helper/urls/Authentication.js.map +0 -1
- package/dist/services/util/CacheService.d.ts +0 -33
- package/dist/services/util/CacheService.js +0 -96
- package/dist/services/util/CacheService.js.map +0 -1
- package/dist/services/util/FetcherService.d.ts +0 -65
- package/dist/services/util/FetcherService.js +0 -202
- package/dist/services/util/FetcherService.js.map +0 -1
- package/dist/types/Args.d.ts +0 -11
- package/dist/types/Args.js +0 -4
- package/dist/types/Args.js.map +0 -1
- package/dist/types/Authentication.d.ts +0 -55
- package/dist/types/Authentication.js +0 -6
- package/dist/types/Authentication.js.map +0 -1
- package/dist/types/Resolvers.d.ts +0 -15
- package/dist/types/Resolvers.js +0 -3
- package/dist/types/Resolvers.js.map +0 -1
- package/dist/types/Rettiwt.d.ts +0 -16
- package/dist/types/Rettiwt.js +0 -3
- package/dist/types/Rettiwt.js.map +0 -1
- package/dist/types/Service.js +0 -5
- package/dist/types/Service.js.map +0 -1
- package/docs/.nojekyll +0 -1
- package/docs/assets/highlight.css +0 -64
- package/docs/assets/main.js +0 -58
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1280
- package/docs/classes/AccountService.html +0 -286
- package/docs/classes/AuthCookie.html +0 -146
- package/docs/classes/AuthService.html +0 -147
- package/docs/classes/CacheService.html +0 -157
- package/docs/classes/Cursor.html +0 -102
- package/docs/classes/CursoredData.html +0 -126
- package/docs/classes/DataValidationError.html +0 -120
- package/docs/classes/FetcherService.html +0 -225
- package/docs/classes/Tweet.html +0 -210
- package/docs/classes/TweetEntities.html +0 -128
- package/docs/classes/TweetFilter.html +0 -223
- package/docs/classes/TweetListArgs.html +0 -118
- package/docs/classes/TweetService.html +0 -319
- package/docs/classes/User.html +0 -230
- package/docs/classes/UserListArgs.html +0 -118
- package/docs/classes/UserService.html +0 -355
- package/docs/enums/HttpMethods.html +0 -74
- package/docs/functions/Rettiwt.html +0 -100
- package/docs/index.html +0 -159
- package/docs/interfaces/IAuthCookie.html +0 -104
- package/docs/interfaces/ICursor.html +0 -77
- package/docs/interfaces/ICursoredData.html +0 -93
- package/docs/interfaces/IDataContext.html +0 -91
- package/docs/interfaces/IDataValidationError.html +0 -109
- package/docs/interfaces/IListArgs.html +0 -87
- package/docs/interfaces/ITweet.html +0 -176
- package/docs/interfaces/ITweetEntities.html +0 -104
- package/docs/interfaces/ITweetFilter.html +0 -158
- package/docs/interfaces/IUser.html +0 -194
- package/docs/modules.html +0 -111
- package/environment.d.ts +0 -11
- package/src/config/env.ts +0 -5
- package/src/enums/Errors.ts +0 -22
- package/src/graphql/enums/Errors.ts +0 -22
- package/src/graphql/queries/RootQuery.ts +0 -75
- package/src/graphql/resolvers/AccountResolver.ts +0 -22
- package/src/graphql/resolvers/ResolverBase.ts +0 -26
- package/src/graphql/resolvers/TweetResolver.ts +0 -237
- package/src/graphql/resolvers/UserResolver.ts +0 -257
- package/src/graphql/types/Global.ts +0 -10
- package/src/graphql/types/TweetTypes.ts +0 -158
- package/src/graphql/types/UserTypes.ts +0 -135
- package/src/models/args/TweetListArgs.ts +0 -47
- package/src/models/args/UserListArgs.ts +0 -47
- package/src/models/auth/AuthCookie.ts +0 -43
- package/src/models/data/CursoredData.ts +0 -45
- package/src/models/data/Tweet.ts +0 -118
- package/src/models/data/User.ts +0 -72
- package/src/server.ts +0 -37
- package/src/services/auth/AccountService.ts +0 -283
- package/src/services/auth/AuthService.ts +0 -81
- package/src/services/data/TweetService.ts +0 -198
- package/src/services/data/UserService.ts +0 -221
- package/src/services/helper/Headers.ts +0 -60
- package/src/services/helper/Parser.ts +0 -89
- package/src/services/helper/extractors/Tweets.ts +0 -190
- package/src/services/helper/extractors/Users.ts +0 -141
- package/src/services/helper/payloads/LoginFlows.ts +0 -90
- package/src/services/helper/urls/Authentication.ts +0 -6
- package/src/services/util/CacheService.ts +0 -76
- package/src/services/util/FetcherService.ts +0 -143
- package/src/types/Args.ts +0 -12
- package/src/types/Authentication.ts +0 -63
- package/src/types/Resolvers.ts +0 -18
- package/src/types/Rettiwt.ts +0 -20
- package/src/types/Service.ts +0 -24
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
// PACKAGES
|
|
2
|
-
import {
|
|
3
|
-
Url,
|
|
4
|
-
EResourceType,
|
|
5
|
-
IUserDetailsResponse,
|
|
6
|
-
IUserFollowersResponse,
|
|
7
|
-
IUserFollowingResponse,
|
|
8
|
-
IUserLikesResponse,
|
|
9
|
-
ITweet as IRawTweet,
|
|
10
|
-
IUser as IRawUser
|
|
11
|
-
} from 'rettiwt-core';
|
|
12
|
-
|
|
13
|
-
// SERVICES
|
|
14
|
-
import { FetcherService } from '../util/FetcherService';
|
|
15
|
-
import { AuthService } from '../auth/AuthService';
|
|
16
|
-
|
|
17
|
-
// MODELS
|
|
18
|
-
import { User } from '../../models/data/User';
|
|
19
|
-
import { UserListArgs } from '../../models/args/UserListArgs';
|
|
20
|
-
import { Tweet } from '../../models/data/Tweet';
|
|
21
|
-
|
|
22
|
-
// TYPES
|
|
23
|
-
import { CursoredData } from '../../models/data/CursoredData';
|
|
24
|
-
|
|
25
|
-
// ENUMS
|
|
26
|
-
import { AuthenticationErrors } from '../../enums/Errors';
|
|
27
|
-
|
|
28
|
-
// EXTRACTORS
|
|
29
|
-
import * as UserExtractors from '../helper/extractors/Users';
|
|
30
|
-
import { TweetService } from './TweetService';
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Handles fetching of data related to user account
|
|
34
|
-
*/
|
|
35
|
-
export class UserService extends FetcherService {
|
|
36
|
-
/**
|
|
37
|
-
* @param auth The AuthService instance to use for authentication.
|
|
38
|
-
*/
|
|
39
|
-
constructor(auth: AuthService) {
|
|
40
|
-
super(auth);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param id The id/username of the target user.
|
|
45
|
-
*
|
|
46
|
-
* @returns The details of the given user.
|
|
47
|
-
*
|
|
48
|
-
* @throws {@link Errors.AuthenticationErrors.NotAuthenticated} error, if no cookies have been provided.
|
|
49
|
-
* @throws {@link Errors.DataErrors.UserNotFound} error, if no user with the given username was found.
|
|
50
|
-
*/
|
|
51
|
-
async getUserDetails(id: string): Promise<User> {
|
|
52
|
-
// If user is not authenticated, abort
|
|
53
|
-
if (!this.isAuthenticated) {
|
|
54
|
-
throw new Error(AuthenticationErrors.NotAuthenticated);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let res: IUserDetailsResponse;
|
|
58
|
-
|
|
59
|
-
// Getting data from cache
|
|
60
|
-
let cachedData = await this.readData(id);
|
|
61
|
-
|
|
62
|
-
// If data exists in cache
|
|
63
|
-
if (cachedData) {
|
|
64
|
-
return cachedData;
|
|
65
|
-
}
|
|
66
|
-
// Else, fetch the data from Twitter instead
|
|
67
|
-
else {
|
|
68
|
-
// Preparing the URL
|
|
69
|
-
const url: string = new Url(EResourceType.USER_DETAILS, { id: id }).toString();
|
|
70
|
-
|
|
71
|
-
// Fetching the raw data
|
|
72
|
-
res = await this.request<IUserDetailsResponse>(url).then(res => res.data);
|
|
73
|
-
|
|
74
|
-
// Extracting data
|
|
75
|
-
let data = UserExtractors.extractUserDetails(res);
|
|
76
|
-
|
|
77
|
-
// Caching data
|
|
78
|
-
this.cacheData(data);
|
|
79
|
-
|
|
80
|
-
// Parsing data
|
|
81
|
-
let user = new User(data.required[0]);
|
|
82
|
-
|
|
83
|
-
return user;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* @param userId The rest id of the target user.
|
|
89
|
-
* @param count The number of tweets to fetch, must be >= 40 (when no cursor is provided) and <=100.
|
|
90
|
-
* @param cursor The cursor to next batch. If blank, first batch is fetched.
|
|
91
|
-
*
|
|
92
|
-
* @returns The list of tweets nade by the target user.
|
|
93
|
-
*
|
|
94
|
-
* @throws {@link Errors.AuthenticationErrors.NotAuthenticated} error, if no cookies have been provided.
|
|
95
|
-
* @throws {@link Errors.ValidationErrors.InvalidCount} error, if invalid count has been provided.
|
|
96
|
-
* @throws {@link Errors.DataErrors.UserNotFound} error, if invalid count has been provided.
|
|
97
|
-
*
|
|
98
|
-
* @deprecated Use [this](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#getTweets) method instead. It's better in every possible way!
|
|
99
|
-
*/
|
|
100
|
-
async getUserTweets(userId: string, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
|
|
101
|
-
// Getting the username of the target user
|
|
102
|
-
const userName: string = (await this.getUserDetails(userId)).userName;
|
|
103
|
-
|
|
104
|
-
// Getting the tweets of the target user
|
|
105
|
-
return new TweetService(this.auth).getTweets({
|
|
106
|
-
fromUsers: [userName]
|
|
107
|
-
}, count, cursor);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* @param userId The rest id of the target user.
|
|
112
|
-
* @param count The number of following to fetch, must be >= 40 (when no cursor is provided) and <=100.
|
|
113
|
-
* @param cursor The cursor to next batch. If blank, first batch is fetched.
|
|
114
|
-
*
|
|
115
|
-
* @returns The list of users followed by the target user.
|
|
116
|
-
*
|
|
117
|
-
* @throws {@link Errors.AuthenticationErrors.NotAuthenticated} error, if no cookies have been provided.
|
|
118
|
-
* @throws {@link Errors.ValidationErrors.InvalidCount} error, if invalid count has been provided.
|
|
119
|
-
* @throws {@link Errors.DataErrors.UserNotFound} error, if invalid count has been provided.
|
|
120
|
-
*/
|
|
121
|
-
async getUserFollowing(userId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
|
|
122
|
-
// If user is not authenticated, abort
|
|
123
|
-
if (!this.isAuthenticated) {
|
|
124
|
-
throw new Error(AuthenticationErrors.NotAuthenticated);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Objectifying parameters
|
|
128
|
-
let args: UserListArgs = new UserListArgs(count, cursor);
|
|
129
|
-
|
|
130
|
-
// Preparing the URL
|
|
131
|
-
const url: string = new Url(EResourceType.USER_FOLLOWING, { id: userId, count: args.count, cursor: args.cursor }).toString();
|
|
132
|
-
|
|
133
|
-
// Fetchin the raw data
|
|
134
|
-
let res = await this.request<IUserFollowingResponse>(url).then(res => res.data);
|
|
135
|
-
|
|
136
|
-
// Extracting data
|
|
137
|
-
let data = UserExtractors.extractUserFollow(res);
|
|
138
|
-
|
|
139
|
-
// Caching data
|
|
140
|
-
this.cacheData(data);
|
|
141
|
-
|
|
142
|
-
// Parsing data
|
|
143
|
-
let users = data.required.map((item: IRawUser) => new User(item));
|
|
144
|
-
|
|
145
|
-
return new CursoredData<User>(users, data.cursor);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* @param userId The rest id of the target user.
|
|
150
|
-
* @param count The number of followers to fetch, must be >= 40 (when no cursor is provided) and <=100.
|
|
151
|
-
* @param cursor The cursor to next batch. If blank, first batch is fetched.
|
|
152
|
-
*
|
|
153
|
-
* @returns The list of users following the target user.
|
|
154
|
-
*
|
|
155
|
-
* @throws {@link Errors.AuthenticationErrors.NotAuthenticated} error, if no cookies have been provided.
|
|
156
|
-
* @throws {@link Errors.ValidationErrors.InvalidCount} error, if invalid count has been provided.
|
|
157
|
-
* @throws {@link Errors.DataErrors.UserNotFound} error, if invalid count has been provided.
|
|
158
|
-
*/
|
|
159
|
-
async getUserFollowers(userId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
|
|
160
|
-
// If user is not authenticated, abort
|
|
161
|
-
if (!this.isAuthenticated) {
|
|
162
|
-
throw new Error(AuthenticationErrors.NotAuthenticated);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Objectifying parameters
|
|
166
|
-
let args: UserListArgs = new UserListArgs(count, cursor);
|
|
167
|
-
|
|
168
|
-
// Preparing the URL
|
|
169
|
-
const url: string = new Url(EResourceType.USER_FOLLOWERS, { id: userId, count: args.count, cursor: args.cursor }).toString();
|
|
170
|
-
|
|
171
|
-
// Fetching the raw data
|
|
172
|
-
let res = await this.request<IUserFollowersResponse>(url).then(res => res.data);
|
|
173
|
-
|
|
174
|
-
// Extracting data
|
|
175
|
-
let data = UserExtractors.extractUserFollow(res);
|
|
176
|
-
|
|
177
|
-
// Caching data
|
|
178
|
-
this.cacheData(data);
|
|
179
|
-
|
|
180
|
-
// Parsing data
|
|
181
|
-
let users = data.required.map((item: IRawUser) => new User(item));
|
|
182
|
-
|
|
183
|
-
return new CursoredData<User>(users, data.cursor);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* @param userId The rest id of the target user.
|
|
188
|
-
* @param count The number of likes to fetch.
|
|
189
|
-
* @param cursor The cursor to next batch. If blank, first batch is fetched, must be >= 40 (when no cursor is provided) and <=100.
|
|
190
|
-
*
|
|
191
|
-
* @returns The list of tweets liked by the target user.
|
|
192
|
-
*
|
|
193
|
-
* @throws {@link AuthenticationErrors.NotAuthenticated} error, if no cookies have been provided.
|
|
194
|
-
*/
|
|
195
|
-
async getUserLikes(userId: string, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
|
|
196
|
-
// If user is not authenticated, abort
|
|
197
|
-
if (!this.isAuthenticated) {
|
|
198
|
-
throw new Error(AuthenticationErrors.NotAuthenticated);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Objectifying parameters
|
|
202
|
-
let args: UserListArgs = new UserListArgs(count, cursor);
|
|
203
|
-
|
|
204
|
-
// Preparing the URL
|
|
205
|
-
const url: string = new Url(EResourceType.USER_LIKES, { id: userId, count: args.count, cursor: args.cursor }).toString();
|
|
206
|
-
|
|
207
|
-
// Fetching the raw data
|
|
208
|
-
let res = await this.request<IUserLikesResponse>(url).then(res => res.data);
|
|
209
|
-
|
|
210
|
-
// Extracting data
|
|
211
|
-
let data = UserExtractors.extractUserLikes(res);
|
|
212
|
-
|
|
213
|
-
// Caching data
|
|
214
|
-
this.cacheData(data);
|
|
215
|
-
|
|
216
|
-
// Parsing data
|
|
217
|
-
let tweets = data.required.map((item: IRawTweet) => new Tweet(item));
|
|
218
|
-
|
|
219
|
-
return new CursoredData<Tweet>(tweets, data.cursor);
|
|
220
|
-
}
|
|
221
|
-
};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// TYPES
|
|
2
|
-
import { IGuestCredentials, IAuthCredentials } from '../../types/Authentication';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param authToken The authentication token received from Twitter
|
|
6
|
-
* @param csrfToken The csrf token received from Twitter
|
|
7
|
-
* @param cookie The cookie associated with the logged in account
|
|
8
|
-
* @returns The header required for making authorized HTTP requests
|
|
9
|
-
*/
|
|
10
|
-
export function authorizedHeader(authCred: IAuthCredentials): any {
|
|
11
|
-
return {
|
|
12
|
-
'sec-ch-ua': '"Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"',
|
|
13
|
-
'x-twitter-client-language': 'en',
|
|
14
|
-
'x-csrf-token': authCred.csrfToken,
|
|
15
|
-
'sec-ch-ua-mobile': '?0',
|
|
16
|
-
'authorization': authCred.authToken,
|
|
17
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.61',
|
|
18
|
-
'x-twitter-auth-type': 'OAuth2Session',
|
|
19
|
-
'x-twitter-active-user': 'yes',
|
|
20
|
-
'sec-ch-ua-platform': '"Windows"',
|
|
21
|
-
'Accept': '*/*',
|
|
22
|
-
'host': 'twitter.com',
|
|
23
|
-
'Cookie': authCred.cookie
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @param guestCred The guest credentials to use
|
|
29
|
-
* @returns The header requred for making guest HTTP requests
|
|
30
|
-
*/
|
|
31
|
-
export function guestHeader(guestCred: IGuestCredentials): any {
|
|
32
|
-
return {
|
|
33
|
-
'Accept': '*/*',
|
|
34
|
-
'authorization': guestCred.authToken,
|
|
35
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70',
|
|
36
|
-
'x-guest-token': guestCred.guestToken
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @param guestCred The guest credentials to use for making the login requests
|
|
42
|
-
* @param cookie The cookie to be used
|
|
43
|
-
* @returns The header for making HTTP request for logging in
|
|
44
|
-
*/
|
|
45
|
-
export function loginHeader(guestCred: IGuestCredentials, cookie: string): any {
|
|
46
|
-
return [
|
|
47
|
-
`sec-ch-ua: "Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"`,
|
|
48
|
-
`x-twitter-client-language: en`,
|
|
49
|
-
`sec-ch-ua-mobile: ?0`,
|
|
50
|
-
`authorization: ${guestCred.authToken}`,
|
|
51
|
-
`User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.78`,
|
|
52
|
-
`content-type: application/json`,
|
|
53
|
-
`x-guest-token: ${guestCred.guestToken}`,
|
|
54
|
-
`x-twitter-active-user: yes`,
|
|
55
|
-
`sec-ch-ua-platform: "Windows"`,
|
|
56
|
-
`Accept: */*`,
|
|
57
|
-
`host: api.twitter.com`,
|
|
58
|
-
`Cookie: ${cookie}`
|
|
59
|
-
];
|
|
60
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
// PACKAGE
|
|
2
|
-
import { ITweetFilter } from 'rettiwt-core';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @returns Whether the given json object is empty or not
|
|
6
|
-
* @param data The input JSON object which needs to be checked
|
|
7
|
-
*/
|
|
8
|
-
export function isJSONEmpty(data: any): boolean {
|
|
9
|
-
// If the JSON has any keys, it's not empty
|
|
10
|
-
if (Object.keys(data).length == 0) {
|
|
11
|
-
return true;
|
|
12
|
-
}
|
|
13
|
-
// Else, it's empty
|
|
14
|
-
else {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @returns The value associated with the given key inside the given json
|
|
21
|
-
* @param data The json data within which to search for the value
|
|
22
|
-
* @param key The key to search for
|
|
23
|
-
* @param last Whether to begin searching from the end
|
|
24
|
-
*/
|
|
25
|
-
export function findJSONKey(data: any, key: string, last: boolean = false): any {
|
|
26
|
-
let jsonStr: string = JSON.stringify(data); // To store the input data as string
|
|
27
|
-
let extStr: string = ''; // To store the extracted string
|
|
28
|
-
let len: number = jsonStr.length; // To store length of input data
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Getting the position to start extracting data from
|
|
32
|
-
* This the position just after the key plus ":"
|
|
33
|
-
* */
|
|
34
|
-
let start: number = !last ? (jsonStr.indexOf(`"${key}"`) + `"${key}":`.length) : (jsonStr.lastIndexOf(`"${key}"`) + `"${key}":`.length);
|
|
35
|
-
|
|
36
|
-
for (let i = start; i < len; i++) {
|
|
37
|
-
// Getting each character
|
|
38
|
-
let char: string = jsonStr[i];
|
|
39
|
-
|
|
40
|
-
// If not ending of value
|
|
41
|
-
if (char != ',' && char != '\n') {
|
|
42
|
-
extStr += char;
|
|
43
|
-
}
|
|
44
|
-
// If ending of value
|
|
45
|
-
else {
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Removing begginning and ending quotes from string
|
|
51
|
-
/**
|
|
52
|
-
* I don't know how this regex I used works. I just copied it from StackOverflow
|
|
53
|
-
* Here is the link to the thread: https://stackoverflow.com/q/19156148
|
|
54
|
-
*/
|
|
55
|
-
extStr = extStr.replace(/^"|"$/g, '');
|
|
56
|
-
|
|
57
|
-
return extStr;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @returns A list of data from a singleton data
|
|
62
|
-
* @param data The data to be converted to a list
|
|
63
|
-
*/
|
|
64
|
-
export function dataToList(data: any | any[]): any[] {
|
|
65
|
-
// If data is already a list
|
|
66
|
-
if (Array.isArray(data)) {
|
|
67
|
-
return data;
|
|
68
|
-
}
|
|
69
|
-
// If data is not array
|
|
70
|
-
else {
|
|
71
|
-
return [data];
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @param text The text to be normalized
|
|
77
|
-
* @returns The text after being formatted to remove unnecessary characters
|
|
78
|
-
*/
|
|
79
|
-
export function normalizeText(text: string): string {
|
|
80
|
-
let normalizedText: string = ''; // To store the normalized text
|
|
81
|
-
|
|
82
|
-
// Removing unnecessary full stops, and other characters
|
|
83
|
-
normalizedText = text.replace(/\n/g, '.').replace(/[.]+[\s+.\s+]+/g, '. ');
|
|
84
|
-
|
|
85
|
-
// Adding full-stop to the end if does not exist already
|
|
86
|
-
normalizedText = normalizedText.endsWith('.') ? normalizedText : (normalizedText + '.');
|
|
87
|
-
|
|
88
|
-
return normalizedText;
|
|
89
|
-
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
// PACKAGE
|
|
2
|
-
import {
|
|
3
|
-
ITweetSearchResponse,
|
|
4
|
-
ITweetDetailsResponse,
|
|
5
|
-
ITweetFavoritersResponse,
|
|
6
|
-
ITweetRetweetersResponse,
|
|
7
|
-
} from 'rettiwt-core';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// TYPES
|
|
11
|
-
import { IDataExtract } from '../../../types/Resolvers';
|
|
12
|
-
import { DataErrors } from '../../../enums/Errors';
|
|
13
|
-
|
|
14
|
-
// PARSERS
|
|
15
|
-
import * as Parsers from '../Parser';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @returns The raw tweets data formatted and sorted into required and additional data
|
|
19
|
-
* @param res The raw response received from TwitterAPI
|
|
20
|
-
*/
|
|
21
|
-
export function extractTweets(res: ITweetSearchResponse): IDataExtract {
|
|
22
|
-
let required: any[] = []; // To store the reqruied raw data
|
|
23
|
-
let cursor: string = ''; // To store the cursor to next batch
|
|
24
|
-
let users: any[] = []; // To store additional user data
|
|
25
|
-
let tweets: any[] = []; // To store additional tweet data
|
|
26
|
-
|
|
27
|
-
// If tweet does not exist
|
|
28
|
-
if (Parsers.isJSONEmpty(res.data.search_by_raw_query)) {
|
|
29
|
-
throw new Error(DataErrors.NoMatchingTweetsFound);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// If tweets
|
|
33
|
-
if (res.data.search_by_raw_query.search_timeline.timeline.instructions.length) {
|
|
34
|
-
// Destructuring raw list of tweets
|
|
35
|
-
res.data.search_by_raw_query.search_timeline.timeline.instructions.filter(item => item.type === 'TimelineAddEntries')[0].entries?.forEach(entry => {
|
|
36
|
-
// If entry is of type tweet and tweet exists
|
|
37
|
-
if (entry.entryId.includes('tweet') && entry.content.itemContent?.tweet_results.result.__typename === 'Tweet') {
|
|
38
|
-
required.push(entry.content.itemContent.tweet_results.result);
|
|
39
|
-
users.push(entry.content.itemContent.tweet_results.result.core?.user_results.result);
|
|
40
|
-
tweets.push(entry.content.itemContent.tweet_results.result);
|
|
41
|
-
}
|
|
42
|
-
// If entry is of type cursor and cursor exists
|
|
43
|
-
else if (entry.entryId.includes('cursor-bottom')) {
|
|
44
|
-
cursor = entry.content.value ?? '';
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
// If cursor not found in 'TimelineAddEntries', getting cursor from 'TimlineReplaceEntry'
|
|
48
|
-
if (!cursor) {
|
|
49
|
-
cursor = res.data.search_by_raw_query.search_timeline.timeline.instructions.filter(item => item.entry_id_to_replace?.includes('cursor-bottom'))[0].entry?.content.value ?? '';
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Returning the data
|
|
54
|
-
return {
|
|
55
|
-
required: required,
|
|
56
|
-
cursor: cursor,
|
|
57
|
-
users: users,
|
|
58
|
-
tweets: tweets
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @returns The raw tweet data formatted and sorted into required and additional data
|
|
64
|
-
* @param res The raw response received from TwitterAPI
|
|
65
|
-
* @param tweetId The rest id of the tweet to fetch
|
|
66
|
-
*/
|
|
67
|
-
export function extractTweet(res: ITweetDetailsResponse, tweetId: string): IDataExtract {
|
|
68
|
-
let required: any[] = []; // To store the reqruied raw data
|
|
69
|
-
let cursor: string = ''; // To store the cursor to next batch
|
|
70
|
-
let users: any[] = []; // To store additional user data
|
|
71
|
-
let tweets: any[] = []; // To store additional tweet data
|
|
72
|
-
|
|
73
|
-
// If tweet does not exist
|
|
74
|
-
if (Parsers.isJSONEmpty(res.data)) {
|
|
75
|
-
throw new Error(DataErrors.TweetNotFound);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Destructuring the received raw data
|
|
79
|
-
res.data.threaded_conversation_with_injections_v2.instructions.filter(item => item['type'] === 'TimelineAddEntries')[0].entries?.forEach(entry => {
|
|
80
|
-
// If entry is of type tweet and tweet exists
|
|
81
|
-
if (entry.entryId.indexOf('tweet') != -1 && entry.content.itemContent?.tweet_results?.result.__typename === 'Tweet') {
|
|
82
|
-
// If this is the required tweet
|
|
83
|
-
if (entry.entryId.indexOf(tweetId) != -1) {
|
|
84
|
-
required.push(entry.content.itemContent.tweet_results.result);
|
|
85
|
-
}
|
|
86
|
-
tweets.push(entry.content.itemContent.tweet_results.result);
|
|
87
|
-
users.push(entry.content.itemContent.tweet_results.result.core.user_results.result);
|
|
88
|
-
}
|
|
89
|
-
// If entry if of type conversation
|
|
90
|
-
else if (entry.entryId.indexOf('conversationthread') != -1) {
|
|
91
|
-
// Iterating over the conversation
|
|
92
|
-
entry.content.items?.forEach(item => {
|
|
93
|
-
// If item is of type tweet and tweet exists
|
|
94
|
-
if (item.entryId.indexOf('tweet') != -1 && item.item.itemContent.tweet_results?.result.__typename === 'Tweet') {
|
|
95
|
-
required.push(item.item.itemContent.tweet_results.result);
|
|
96
|
-
tweets.push(item.item.itemContent.tweet_results.result);
|
|
97
|
-
users.push(item.item.itemContent.tweet_results.result.core.user_results.result);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// Returning the data
|
|
104
|
-
return {
|
|
105
|
-
required: required,
|
|
106
|
-
cursor: cursor,
|
|
107
|
-
users: users,
|
|
108
|
-
tweets: tweets
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* @returns The raw tweet likers data formatted and sorted into required and additional data
|
|
114
|
-
* @param res The raw response received from TwitterAPI
|
|
115
|
-
*/
|
|
116
|
-
export function extractTweetLikers(res: ITweetFavoritersResponse): IDataExtract {
|
|
117
|
-
let required: any[] = []; // To store the reqruied raw data
|
|
118
|
-
let cursor: string = ''; // To store the cursor to next batch
|
|
119
|
-
let users: any[] = []; // To store additional user data
|
|
120
|
-
let tweets: any[] = []; // To store additional tweet data
|
|
121
|
-
|
|
122
|
-
// If tweet does not exist
|
|
123
|
-
if (Parsers.isJSONEmpty(res.data.favoriters_timeline)) {
|
|
124
|
-
throw new Error(DataErrors.TweetNotFound);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// If likes found
|
|
128
|
-
if (res.data.favoriters_timeline.timeline.instructions.length) {
|
|
129
|
-
// Destructuring raw list of likers
|
|
130
|
-
res.data.favoriters_timeline.timeline.instructions.filter(item => item.type === 'TimelineAddEntries')[0].entries.forEach(entry => {
|
|
131
|
-
// If entry is of type user and user exists
|
|
132
|
-
if (entry.entryId.indexOf('user') != -1 && entry.content.itemContent?.user_results.result.__typename === 'User') {
|
|
133
|
-
required.push(entry.content.itemContent.user_results.result);
|
|
134
|
-
users.push(entry.content.itemContent.user_results.result);
|
|
135
|
-
}
|
|
136
|
-
// If entry is of type cursor
|
|
137
|
-
else if (entry.entryId.indexOf('cursor-bottom') != -1) {
|
|
138
|
-
cursor = entry.content.value ?? '';
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Returning the data
|
|
144
|
-
return {
|
|
145
|
-
required: required,
|
|
146
|
-
cursor: cursor,
|
|
147
|
-
users: users,
|
|
148
|
-
tweets: tweets
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* @returns The raw tweet retweeters data formatted and sorted into required and additional data
|
|
154
|
-
* @param res The raw response received from TwitterAPI
|
|
155
|
-
*/
|
|
156
|
-
export function extractTweetRetweeters(res: ITweetRetweetersResponse): IDataExtract {
|
|
157
|
-
let required: any[] = []; // To store the reqruied raw data
|
|
158
|
-
let cursor: string = ''; // To store the cursor to next batch
|
|
159
|
-
let users: any[] = []; // To store additional user data
|
|
160
|
-
let tweets: any[] = []; // To store additional tweet data
|
|
161
|
-
|
|
162
|
-
// If tweet does not exist
|
|
163
|
-
if (Parsers.isJSONEmpty(res.data.retweeters_timeline)) {
|
|
164
|
-
throw new Error(DataErrors.TweetNotFound);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// If retweeters found
|
|
168
|
-
if (res.data.retweeters_timeline.timeline.instructions.length) {
|
|
169
|
-
// Destructuring raw list of retweeters
|
|
170
|
-
res.data.retweeters_timeline.timeline.instructions.filter(item => item.type === 'TimelineAddEntries')[0].entries.forEach(entry => {
|
|
171
|
-
// If entry is of type user and user exists
|
|
172
|
-
if (entry.entryId.indexOf('user') != -1 && entry.content.itemContent?.user_results.result.__typename === 'User') {
|
|
173
|
-
required.push(entry.content.itemContent.user_results.result);
|
|
174
|
-
users.push(entry.content.itemContent.user_results.result);
|
|
175
|
-
}
|
|
176
|
-
// If entry is of type cursor
|
|
177
|
-
else if (entry.entryId.indexOf('cursor-bottom') != -1) {
|
|
178
|
-
cursor = entry.content.value ?? '';
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Returning the data
|
|
184
|
-
return {
|
|
185
|
-
required: required,
|
|
186
|
-
cursor: cursor,
|
|
187
|
-
users: users,
|
|
188
|
-
tweets: tweets
|
|
189
|
-
};
|
|
190
|
-
}
|