rettiwt-api 1.0.5 → 1.0.7
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 +2 -2
- package/dist/{queries → graphql/queries}/RootQuery.d.ts +0 -0
- package/dist/{queries → graphql/queries}/RootQuery.js +15 -3
- package/dist/graphql/queries/RootQuery.js.map +1 -0
- package/dist/graphql/resolvers/AccountResolver.d.ts +12 -0
- package/dist/graphql/resolvers/AccountResolver.js +84 -0
- package/dist/graphql/resolvers/AccountResolver.js.map +1 -0
- package/dist/{resolvers → graphql/resolvers}/ResolverBase.d.ts +1 -1
- package/dist/{resolvers → graphql/resolvers}/ResolverBase.js +0 -0
- package/dist/graphql/resolvers/ResolverBase.js.map +1 -0
- package/dist/{resolvers → graphql/resolvers}/TweetResolver.d.ts +10 -9
- package/dist/{resolvers → graphql/resolvers}/TweetResolver.js +51 -35
- package/dist/graphql/resolvers/TweetResolver.js.map +1 -0
- package/dist/{resolvers → graphql/resolvers}/UserResolver.d.ts +5 -4
- package/dist/{resolvers → graphql/resolvers}/UserResolver.js +51 -35
- package/dist/graphql/resolvers/UserResolver.js.map +1 -0
- package/dist/{models/graphql → graphql/types}/Global.d.ts +0 -0
- package/dist/{models/graphql → graphql/types}/Global.js +0 -0
- package/dist/graphql/types/Global.js.map +1 -0
- package/dist/graphql/types/TweetTypes.d.ts +4 -0
- package/dist/{models/graphql → graphql/types}/TweetTypes.js +5 -7
- package/dist/graphql/types/TweetTypes.js.map +1 -0
- package/dist/graphql/types/UserTypes.d.ts +3 -0
- package/dist/{models/graphql → graphql/types}/UserTypes.js +9 -11
- package/dist/graphql/types/UserTypes.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/server.js +6 -4
- package/dist/server.js.map +1 -1
- package/dist/services/AuthService.js +2 -2
- package/dist/services/AuthService.js.map +1 -1
- package/dist/services/CacheService.d.ts +3 -3
- package/dist/services/CacheService.js +22 -75
- package/dist/services/CacheService.js.map +1 -1
- package/dist/services/FetcherService.d.ts +14 -4
- package/dist/services/FetcherService.js +58 -52
- package/dist/services/FetcherService.js.map +1 -1
- package/dist/services/accounts/AccountService.d.ts +42 -0
- package/dist/services/accounts/AccountService.js +291 -0
- package/dist/services/accounts/AccountService.js.map +1 -0
- package/dist/services/accounts/LoginFlows.d.ts +77 -0
- package/dist/services/accounts/LoginFlows.js +92 -0
- package/dist/services/accounts/LoginFlows.js.map +1 -0
- package/dist/services/data/TweetService.d.ts +6 -6
- package/dist/services/data/TweetService.js +44 -27
- package/dist/services/data/TweetService.js.map +1 -1
- package/dist/services/data/UserAccountService.d.ts +3 -3
- package/dist/services/data/UserAccountService.js +22 -8
- package/dist/services/data/UserAccountService.js.map +1 -1
- package/dist/services/data/UserService.d.ts +42 -0
- package/dist/services/data/UserService.js +255 -0
- package/dist/services/data/UserService.js.map +1 -0
- package/dist/services/helper/Extractors.js +1 -1
- package/dist/services/helper/Extractors.js.map +1 -1
- package/dist/services/helper/Headers.d.ts +11 -1
- package/dist/services/helper/Headers.js +28 -2
- package/dist/services/helper/Headers.js.map +1 -1
- package/dist/services/helper/Parser.d.ts +1 -1
- package/dist/services/helper/Parser.js +4 -3
- package/dist/services/helper/Parser.js.map +1 -1
- package/dist/services/helper/Urls.d.ts +2 -2
- package/dist/services/helper/Urls.js +19 -3
- package/dist/services/helper/Urls.js.map +1 -1
- package/dist/services/helper/deserializers/Tweets.d.ts +12 -0
- package/dist/services/helper/deserializers/Tweets.js +92 -0
- package/dist/services/helper/deserializers/Tweets.js.map +1 -0
- package/dist/services/helper/deserializers/User.d.ts +0 -0
- package/dist/services/helper/deserializers/User.js +2 -0
- package/dist/services/helper/deserializers/User.js.map +1 -0
- package/dist/services/helper/deserializers/Users.d.ts +7 -0
- package/dist/services/helper/deserializers/Users.js +27 -0
- package/dist/services/helper/deserializers/Users.js.map +1 -0
- package/dist/services/helper/extractors/TweetExtractors.d.ts +0 -0
- package/dist/services/helper/extractors/TweetExtractors.js +2 -0
- package/dist/services/helper/extractors/TweetExtractors.js.map +1 -0
- package/dist/services/helper/extractors/Tweets.d.ts +32 -0
- package/dist/services/helper/extractors/Tweets.js +264 -0
- package/dist/services/helper/extractors/Tweets.js.map +1 -0
- package/dist/services/helper/extractors/UserExtractors.d.ts +45 -0
- package/dist/services/helper/extractors/UserExtractors.js +176 -0
- package/dist/services/helper/extractors/UserExtractors.js.map +1 -0
- package/dist/services/helper/extractors/Users.d.ts +20 -0
- package/dist/services/helper/extractors/Users.js +151 -0
- package/dist/services/helper/extractors/Users.js.map +1 -0
- package/dist/services/helper/urls/Authentication.d.ts +4 -0
- package/dist/services/helper/urls/Authentication.js +11 -0
- package/dist/services/helper/urls/Authentication.js.map +1 -0
- package/dist/services/helper/urls/Tweets.d.ts +32 -0
- package/dist/services/helper/urls/Tweets.js +51 -0
- package/dist/services/helper/urls/Tweets.js.map +1 -0
- package/dist/services/helper/urls/Urls.d.ts +4 -0
- package/dist/services/helper/urls/Urls.js +11 -0
- package/dist/services/helper/urls/Urls.js.map +1 -0
- package/dist/services/helper/urls/Users.d.ts +31 -0
- package/dist/services/helper/urls/Users.js +66 -0
- package/dist/services/helper/urls/Users.js.map +1 -0
- package/dist/types/{graphql/Errors.d.ts → Errors.d.ts} +0 -0
- package/dist/types/{graphql/Errors.js → Errors.js} +0 -0
- package/dist/types/Errors.js.map +1 -0
- package/dist/types/HTTP.d.ts +0 -7
- package/dist/types/HTTP.js +1 -10
- package/dist/types/HTTP.js.map +1 -1
- package/dist/types/Resolvers.d.ts +9 -0
- package/dist/types/Resolvers.js +3 -0
- package/dist/types/Resolvers.js.map +1 -0
- package/dist/types/Service.d.ts +2 -0
- package/dist/types/Service.js.map +1 -1
- package/dist/types/Tweet.d.ts +1 -0
- package/dist/types/Tweet.js.map +1 -1
- package/dist/types/User.d.ts +19 -0
- package/dist/types/User.js +4 -0
- package/dist/types/User.js.map +1 -0
- package/dist/types/data/Errors.d.ts +26 -0
- package/dist/types/data/Errors.js +36 -0
- package/dist/types/data/Errors.js.map +1 -0
- package/dist/types/data/Service.d.ts +29 -0
- package/dist/types/data/Service.js +19 -0
- package/dist/types/data/Service.js.map +1 -0
- package/dist/types/data/Tweet.d.ts +41 -0
- package/dist/types/data/Tweet.js +5 -0
- package/dist/types/data/Tweet.js.map +1 -0
- package/dist/types/data/User.d.ts +19 -0
- package/dist/types/data/User.js +4 -0
- package/dist/types/data/User.js.map +1 -0
- package/dist/types/raw/http/Error.d.ts +34 -0
- package/dist/types/raw/{user/Users.js → http/Error.js} +1 -1
- package/dist/types/raw/http/Error.js.map +1 -0
- package/dist/types/raw/http/Response.d.ts +34 -0
- package/dist/types/raw/http/Response.js +3 -0
- package/dist/types/raw/http/Response.js.map +1 -0
- package/package.json +4 -2
- package/src/{queries → graphql/queries}/RootQuery.ts +16 -4
- package/src/graphql/resolvers/AccountResolver.ts +22 -0
- package/src/{resolvers → graphql/resolvers}/ResolverBase.ts +1 -1
- package/src/{resolvers → graphql/resolvers}/TweetResolver.ts +43 -30
- package/src/{resolvers → graphql/resolvers}/UserResolver.ts +41 -27
- package/src/{models/graphql → graphql/types}/Global.ts +0 -0
- package/src/{models/graphql → graphql/types}/TweetTypes.ts +9 -11
- package/src/{models/graphql → graphql/types}/UserTypes.ts +13 -15
- package/src/index.ts +5 -3
- package/src/server.ts +6 -4
- package/src/services/AuthService.ts +1 -1
- package/src/services/CacheService.ts +6 -8
- package/src/services/FetcherService.ts +37 -22
- package/src/services/accounts/AccountService.ts +156 -0
- package/src/services/accounts/LoginFlows.ts +90 -0
- package/src/services/data/TweetService.ts +53 -37
- package/src/services/data/UserService.ts +187 -0
- package/src/services/helper/Headers.ts +27 -1
- package/src/services/helper/Parser.ts +6 -4
- package/src/services/helper/{Deserializers.ts → deserializers/Tweets.ts} +3 -28
- package/src/services/helper/deserializers/Users.ts +26 -0
- package/src/services/helper/extractors/Tweets.ts +252 -0
- package/src/services/helper/extractors/Users.ts +137 -0
- package/src/services/helper/urls/Authentication.ts +6 -0
- package/src/services/helper/urls/Tweets.ts +46 -0
- package/src/services/helper/urls/Users.ts +62 -0
- package/src/types/HTTP.ts +0 -8
- package/src/types/Resolvers.ts +9 -0
- package/src/types/data/Errors.ts +28 -0
- package/src/types/{Service.ts → data/Service.ts} +6 -5
- package/src/types/{Tweet.ts → data/Tweet.ts} +1 -0
- package/src/types/{UserAccount.ts → data/User.ts} +0 -0
- package/tsconfig.json +2 -2
- package/dist/models/graphql/Global.js.map +0 -1
- package/dist/models/graphql/TweetTypes.d.ts +0 -6
- package/dist/models/graphql/TweetTypes.js.map +0 -1
- package/dist/models/graphql/UserTypes.d.ts +0 -3
- package/dist/models/graphql/UserTypes.js.map +0 -1
- package/dist/queries/RootQuery.js.map +0 -1
- package/dist/resolvers/ResolverBase.js.map +0 -1
- package/dist/resolvers/TweetResolver.js.map +0 -1
- package/dist/resolvers/UserResolver.js.map +0 -1
- package/dist/test/Test.js +0 -2
- package/dist/test/Test.js.map +0 -1
- package/dist/types/graphql/Errors.js.map +0 -1
- package/dist/types/raw/user/Users.d.ts +0 -120
- package/dist/types/raw/user/Users.js.map +0 -1
- package/src/services/data/UserAccountService.ts +0 -176
- package/src/services/helper/Extractors.ts +0 -455
- package/src/services/helper/Urls.ts +0 -109
- package/src/types/graphql/Errors.ts +0 -16
- package/src/types/raw/user/Tweets.ts +0 -2847
|
@@ -12,7 +12,17 @@ import { Result as RawTweet } from '../types/raw/tweet/Tweet';
|
|
|
12
12
|
|
|
13
13
|
// HELPERS
|
|
14
14
|
import * as Headers from './helper/Headers'
|
|
15
|
-
import * as
|
|
15
|
+
import * as UserDeserializers from './helper/deserializers/Users';
|
|
16
|
+
import * as TweetDeserializers from './helper/deserializers/Tweets';
|
|
17
|
+
import { CurlyOptions } from 'node-libcurl/dist/curly';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @summary Stores all the different type of http requests
|
|
21
|
+
*/
|
|
22
|
+
export enum HttpMethods {
|
|
23
|
+
POST = "POST",
|
|
24
|
+
GET = "GET"
|
|
25
|
+
};
|
|
16
26
|
|
|
17
27
|
/**
|
|
18
28
|
* @service The base serivice from which all other data services derive their behaviour
|
|
@@ -20,11 +30,13 @@ import * as Deserializers from './helper/Deserializers';
|
|
|
20
30
|
export class FetcherService {
|
|
21
31
|
// MEMBER DATA
|
|
22
32
|
private auth: AuthService; // To store the auth service instance to use for authentication
|
|
33
|
+
private cache: CacheService; // To stoer the cache service instance to use for caching data
|
|
23
34
|
protected isAuthenticated: boolean; // To store whether user is authenticated or not
|
|
24
35
|
|
|
25
36
|
// MEMBER METHODS
|
|
26
37
|
constructor(auth: AuthService) {
|
|
27
38
|
this.auth = auth;
|
|
39
|
+
this.cache = CacheService.getInstance();
|
|
28
40
|
this.isAuthenticated = this.auth.isAuthenticated;
|
|
29
41
|
}
|
|
30
42
|
|
|
@@ -43,44 +55,47 @@ export class FetcherService {
|
|
|
43
55
|
/**
|
|
44
56
|
* @returns The absolute raw json data from give url
|
|
45
57
|
* @param url The url to fetch data from
|
|
46
|
-
* @param
|
|
58
|
+
* @param authenticate Whether to authenticate requests or not
|
|
59
|
+
* @param method The HTTP method to use
|
|
60
|
+
* @param data The data to be sent along with the request (works with only POST method)
|
|
47
61
|
*/
|
|
48
|
-
protected async request<DataType>(url: string,
|
|
49
|
-
//
|
|
50
|
-
let
|
|
51
|
-
httpHeader:
|
|
52
|
-
sslVerifyPeer: false
|
|
53
|
-
}
|
|
62
|
+
protected async request<DataType>(url: string, authenticate: boolean = true, method: HttpMethods = HttpMethods.GET, data?: any): Promise<CurlyResult<DataType>> {
|
|
63
|
+
// Creating the configuration for the http request
|
|
64
|
+
let config: CurlyOptions = {
|
|
65
|
+
httpHeader: authenticate ? Headers.authorizedHeader(await this.auth.getAuthCredentials()) : Headers.guestHeader(await this.auth.getGuestCredentials()),
|
|
66
|
+
sslVerifyPeer: false,
|
|
67
|
+
};
|
|
54
68
|
|
|
55
|
-
|
|
69
|
+
// If post request is to be made
|
|
70
|
+
if (method == HttpMethods.POST) {
|
|
71
|
+
return await curly.post(url, { ...config, postFields: JSON.stringify(data) }).then(res => this.handleHTTPError(res));
|
|
72
|
+
}
|
|
73
|
+
// If get request is to be made
|
|
74
|
+
else {
|
|
75
|
+
return await curly.get(url, config).then(res => this.handleHTTPError(res));
|
|
76
|
+
}
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
/**
|
|
59
80
|
* @summary Caches the extracted data
|
|
60
81
|
* @param data The extracted data to be cached
|
|
61
82
|
*/
|
|
62
|
-
protected
|
|
63
|
-
// Creating an instance of cache
|
|
64
|
-
let cache = await CacheService.getInstance();
|
|
65
|
-
|
|
83
|
+
protected cacheData(data: any): void {
|
|
66
84
|
// Parsing the extracted data
|
|
67
|
-
let users = data.users.map((user: RawUser) =>
|
|
68
|
-
let tweets = data.tweets.map((tweet: RawTweet) =>
|
|
85
|
+
let users = data.users.map((user: RawUser) => UserDeserializers.toUser(user));
|
|
86
|
+
let tweets = data.tweets.map((tweet: RawTweet) => TweetDeserializers.toTweet(tweet));
|
|
69
87
|
|
|
70
88
|
// Caching the data
|
|
71
|
-
cache.write(users);
|
|
72
|
-
cache.write(tweets);
|
|
89
|
+
this.cache.write(users);
|
|
90
|
+
this.cache.write(tweets);
|
|
73
91
|
}
|
|
74
92
|
|
|
75
93
|
/**
|
|
76
94
|
* @returns The data with the given id (if it exists in cache)
|
|
77
95
|
* @param id The id of the data to be read from cache
|
|
78
96
|
*/
|
|
79
|
-
protected
|
|
80
|
-
// Creating an instance of cache
|
|
81
|
-
let cache = await CacheService.getInstance();
|
|
82
|
-
|
|
97
|
+
protected readData(id: string): any {
|
|
83
98
|
// Reading data from cache
|
|
84
|
-
return cache.read(id);
|
|
99
|
+
return this.cache.read(id);
|
|
85
100
|
}
|
|
86
101
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// PACKAGES
|
|
2
|
+
import { curly, CurlyResult } from 'node-libcurl';
|
|
3
|
+
|
|
4
|
+
// SERVICES
|
|
5
|
+
import { AuthService } from '../AuthService';
|
|
6
|
+
|
|
7
|
+
// TYPES
|
|
8
|
+
import { GuestCredentials } from '../../types/Authentication';
|
|
9
|
+
|
|
10
|
+
// HELPERS
|
|
11
|
+
import LoginFlows from './LoginFlows';
|
|
12
|
+
import { loginHeader } from '../helper/Headers';
|
|
13
|
+
import { Cookie, CookieJar } from 'cookiejar';
|
|
14
|
+
|
|
15
|
+
export class AccountService {
|
|
16
|
+
// MEMBER DATA
|
|
17
|
+
private auth: AuthService; // To store the auth service instance to use
|
|
18
|
+
private guestCreds: GuestCredentials; // To store the guest credentials to use
|
|
19
|
+
private cookies: Cookie[]; // To store the cookies received from twitter
|
|
20
|
+
private flowToken: string; // To store the flow token received from current flow
|
|
21
|
+
|
|
22
|
+
// MEMBER METHODS
|
|
23
|
+
constructor() {
|
|
24
|
+
this.auth = new AuthService();
|
|
25
|
+
this.guestCreds = { authToken: '', guestToken: '' };
|
|
26
|
+
this.cookies = [];
|
|
27
|
+
this.flowToken = '';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @returns The current guest credentials to use. If if does not exists, then a new one is created
|
|
32
|
+
*/
|
|
33
|
+
private async getGuestCredentials(): Promise<GuestCredentials> {
|
|
34
|
+
// If a guest credential has not been already set, get a new one
|
|
35
|
+
if (!this.guestCreds.guestToken) {
|
|
36
|
+
this.guestCreds = await this.auth.getGuestCredentials();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return this.guestCreds;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @summary Step 1: Initiates login
|
|
44
|
+
*/
|
|
45
|
+
private async initiateLogin(): Promise<void> {
|
|
46
|
+
// Initiating the login process
|
|
47
|
+
const res: CurlyResult = await curly.post(LoginFlows.InitiateLogin.url, {
|
|
48
|
+
httpHeader: loginHeader(await this.getGuestCredentials(), this.cookies.toString()),
|
|
49
|
+
sslVerifyPeer: false,
|
|
50
|
+
postFields: ''
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Storing cookies received
|
|
54
|
+
this.cookies = new CookieJar().setCookies(res.headers[0]['Set-Cookie'] as string[]);
|
|
55
|
+
|
|
56
|
+
// Getting the flow token
|
|
57
|
+
this.flowToken = res.data['flow_token'];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @summary Step 2: Does something
|
|
62
|
+
*/
|
|
63
|
+
private async jsInstrumentationSubtask(): Promise<void> {
|
|
64
|
+
// Executing the flow
|
|
65
|
+
const res: CurlyResult = await curly.post(LoginFlows.JsInstrumentationSubtask.url, {
|
|
66
|
+
httpHeader: loginHeader(await this.getGuestCredentials(), this.cookies.join(';').toString()),
|
|
67
|
+
sslVerifyPeer: false,
|
|
68
|
+
postFields: JSON.stringify(LoginFlows.JsInstrumentationSubtask.body(this.flowToken))
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Getting the flow token
|
|
72
|
+
this.flowToken = res.data['flow_token'];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @summary Step 3: Takes the email for login
|
|
77
|
+
*/
|
|
78
|
+
private async enterUserIdentifier(email: string): Promise<void> {
|
|
79
|
+
// Executing the flow
|
|
80
|
+
const res: CurlyResult = await curly.post(LoginFlows.EnterUserIdentifier.url, {
|
|
81
|
+
httpHeader: loginHeader(await this.getGuestCredentials(), this.cookies.join(';').toString()),
|
|
82
|
+
sslVerifyPeer: false,
|
|
83
|
+
postFields: JSON.stringify(LoginFlows.EnterUserIdentifier.body(this.flowToken, email))
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Getting the flow token
|
|
87
|
+
this.flowToken = res.data['flow_token'];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @summary Step 4: Takes the username for login
|
|
92
|
+
*/
|
|
93
|
+
private async enterAlternateUserIdentifier(userName: string): Promise<void> {
|
|
94
|
+
// Executing the flow
|
|
95
|
+
const res: CurlyResult = await curly.post(LoginFlows.EnterAlternateUserIdentifier.url, {
|
|
96
|
+
httpHeader: loginHeader(await this.getGuestCredentials(), this.cookies.join(';').toString()),
|
|
97
|
+
sslVerifyPeer: false,
|
|
98
|
+
postFields: JSON.stringify(LoginFlows.EnterAlternateUserIdentifier.body(this.flowToken, userName))
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Getting the flow token
|
|
102
|
+
this.flowToken = res.data['flow_token'];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @summary Step 5: Takes the password for login
|
|
107
|
+
*/
|
|
108
|
+
private async enterPassword(password: string): Promise<void> {
|
|
109
|
+
// Executing the flow
|
|
110
|
+
const res: CurlyResult = await curly.post(LoginFlows.EnterPassword.url, {
|
|
111
|
+
httpHeader: loginHeader(await this.getGuestCredentials(), this.cookies.join(';').toString()),
|
|
112
|
+
sslVerifyPeer: false,
|
|
113
|
+
postFields: JSON.stringify(LoginFlows.EnterPassword.body(this.flowToken, password))
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Getting the flow token
|
|
117
|
+
this.flowToken = res.data['flow_token'];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @summary Step 6: Gets the actual cookies
|
|
122
|
+
*/
|
|
123
|
+
private async accountDuplicationCheck(): Promise<void> {
|
|
124
|
+
// Executing the flow
|
|
125
|
+
const res: CurlyResult = await curly.post(LoginFlows.AccountDuplicationCheck.url, {
|
|
126
|
+
httpHeader: loginHeader(await this.getGuestCredentials(), this.cookies.join(';').toString()),
|
|
127
|
+
sslVerifyPeer: false,
|
|
128
|
+
postFields: JSON.stringify(LoginFlows.AccountDuplicationCheck.body(this.flowToken))
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Storing cookies received
|
|
132
|
+
this.cookies = new CookieJar().setCookies(res.headers[0]['Set-Cookie'] as string[]);
|
|
133
|
+
|
|
134
|
+
// Getting the flow token
|
|
135
|
+
this.flowToken = res.data['flow_token'];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param email The email of the account to be logged into
|
|
140
|
+
* @param userName The username associated with the given account
|
|
141
|
+
* @param password The password to the account
|
|
142
|
+
* @returns The cookies for authenticating with the given account
|
|
143
|
+
*/
|
|
144
|
+
public async login(email: string, userName: string, password: string): Promise<string> {
|
|
145
|
+
// Executing each step of login flow
|
|
146
|
+
await this.initiateLogin();
|
|
147
|
+
await this.jsInstrumentationSubtask();
|
|
148
|
+
await this.enterUserIdentifier(email);
|
|
149
|
+
await this.enterAlternateUserIdentifier(userName);
|
|
150
|
+
await this.enterPassword(password);
|
|
151
|
+
await this.accountDuplicationCheck();
|
|
152
|
+
|
|
153
|
+
// Returning the final cookies
|
|
154
|
+
return this.cookies.join(';');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const LoginFlows = {
|
|
2
|
+
"InitiateLogin": {
|
|
3
|
+
url: 'https://api.twitter.com/1.1/onboarding/task.json?flow_name=login'
|
|
4
|
+
},
|
|
5
|
+
"JsInstrumentationSubtask": {
|
|
6
|
+
url: 'https://api.twitter.com/1.1/onboarding/task.json',
|
|
7
|
+
body: (flowToken: string) => ({
|
|
8
|
+
"flow_token": flowToken,
|
|
9
|
+
"subtask_inputs": [
|
|
10
|
+
{
|
|
11
|
+
"subtask_id": "LoginJsInstrumentationSubtask",
|
|
12
|
+
"js_instrumentation": {
|
|
13
|
+
"response": "{\"rf\":{\"a09453c7341fb1cbb7d51561f92d478fa0752bc77e7ca6b5703258680b2c51d7\":-4,\"bd26c6694e256b10766447d992deaf92bb220bc05e3b8205ba5c9a4f83302230\":0,\"abfa440376b8dc33ca518e1e2a998b3ac4200a8122ef09781eea2c1408717111\":-1,\"a4e87b66027f638a4634561275fab00f9f7446b81a180b5f03eda69fa32eb8f4\":-224},\"s\":\"yET9nlXrlGRAylCyyBKEsxOpUweMpjRz5RfKzTzQyVADnKE64gmpyILfKBK0-HIHWY8FbJPHGWr6QrCb5A-Z3q2SLRm4DReprZGXykJ111_ynet8kSjFkRjODKKDN2FzT1V6rx9FILnUuRCaMu9ewfPgPBi4wO1g7EUeEsSSHIiCwNc9URJr4c2xVTA3ibIfTbu8p2WhX7RZAk8LWRPpPPB21st8Z1j0LcLlR0bkZoF6LsN-7w75lGB0s4z1JKqus2MVuRcPMay0wWZbn8Qx9In_-tSTvEBLcxjUpDgwu29G0g0iCWoISFzLY4-LLvV7UBGklkByIcPtwYbDbREqRQAAAYYmXAsG\"}",
|
|
14
|
+
"link": "next_link"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
})
|
|
19
|
+
},
|
|
20
|
+
"EnterUserIdentifier": {
|
|
21
|
+
url: 'https://api.twitter.com/1.1/onboarding/task.json',
|
|
22
|
+
body: (flowToken: string, email: string) => ({
|
|
23
|
+
"flow_token": flowToken,
|
|
24
|
+
"subtask_inputs": [
|
|
25
|
+
{
|
|
26
|
+
"subtask_id": "LoginEnterUserIdentifierSSO",
|
|
27
|
+
"settings_list": {
|
|
28
|
+
"setting_responses": [
|
|
29
|
+
{
|
|
30
|
+
"key": "user_identifier",
|
|
31
|
+
"response_data": {
|
|
32
|
+
"text_data": {
|
|
33
|
+
"result": email
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"link": "next_link"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
})
|
|
43
|
+
},
|
|
44
|
+
"EnterAlternateUserIdentifier": {
|
|
45
|
+
url: 'https://api.twitter.com/1.1/onboarding/task.json',
|
|
46
|
+
body: (flowToken: string, userName: string) => ({
|
|
47
|
+
"flow_token": flowToken,
|
|
48
|
+
"subtask_inputs": [
|
|
49
|
+
{
|
|
50
|
+
"subtask_id": "LoginEnterAlternateIdentifierSubtask",
|
|
51
|
+
"enter_text": {
|
|
52
|
+
"text": userName,
|
|
53
|
+
"link": "next_link"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
})
|
|
58
|
+
},
|
|
59
|
+
"EnterPassword": {
|
|
60
|
+
url: 'https://api.twitter.com/1.1/onboarding/task.json',
|
|
61
|
+
body: (flowToken: string, password: string) => ({
|
|
62
|
+
"flow_token": flowToken,
|
|
63
|
+
"subtask_inputs": [
|
|
64
|
+
{
|
|
65
|
+
"subtask_id": "LoginEnterPassword",
|
|
66
|
+
"enter_password": {
|
|
67
|
+
"password": password,
|
|
68
|
+
"link": "next_link"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
},
|
|
74
|
+
"AccountDuplicationCheck": {
|
|
75
|
+
url: 'https://api.twitter.com/1.1/onboarding/task.json',
|
|
76
|
+
body: (flowToken: string) => ({
|
|
77
|
+
"flow_token": flowToken,
|
|
78
|
+
"subtask_inputs": [
|
|
79
|
+
{
|
|
80
|
+
"subtask_id": "AccountDuplicationCheck",
|
|
81
|
+
"check_logged_in_account": {
|
|
82
|
+
"link": "AccountDuplicationCheck_false"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default LoginFlows;
|
|
@@ -3,22 +3,25 @@ import { FetcherService } from "../FetcherService";
|
|
|
3
3
|
import { AuthService } from "../AuthService";
|
|
4
4
|
|
|
5
5
|
// TYPES
|
|
6
|
-
import { TweetFilter, Tweet } from "../../types/Tweet";
|
|
7
|
-
import { User } from "../../types/
|
|
8
|
-
import { CursoredData } from '../../types/Service';
|
|
9
|
-
import RawTweet from '../../types/raw/tweet/Tweet';
|
|
6
|
+
import { TweetFilter, Tweet } from "../../types/data/Tweet";
|
|
7
|
+
import { User } from "../../types/data/User";
|
|
8
|
+
import { CursoredData } from '../../types/data/Service';
|
|
9
|
+
import RawTweet, { Result as TweetData } from '../../types/raw/tweet/Tweet';
|
|
10
|
+
import { Result as UserData } from "../../types/raw/user/User";
|
|
10
11
|
import RawTweets from '../../types/raw/tweet/Tweets';
|
|
11
12
|
import RawLikers from '../../types/raw/tweet/Favouriters';
|
|
12
13
|
import RawRetweeters from '../../types/raw/tweet/Retweeters';
|
|
14
|
+
import * as Errors from '../../types/data/Errors';
|
|
13
15
|
|
|
14
16
|
// URLS
|
|
15
|
-
import * as
|
|
17
|
+
import * as TweetUrls from '../helper/urls/Tweets';
|
|
16
18
|
|
|
17
19
|
// EXTRACTORS
|
|
18
|
-
import * as
|
|
20
|
+
import * as TweetExtractors from "../helper/extractors/Tweets";
|
|
19
21
|
|
|
20
22
|
// DESERIALIZERS
|
|
21
|
-
import * as
|
|
23
|
+
import * as UserDeserializers from '../helper/deserializers/Users';
|
|
24
|
+
import * as TweetDeserializers from '../helper/deserializers/Tweets';
|
|
22
25
|
|
|
23
26
|
// PARSERS
|
|
24
27
|
import { toQueryString } from '../helper/Parser';
|
|
@@ -35,21 +38,26 @@ export class TweetService extends FetcherService {
|
|
|
35
38
|
/**
|
|
36
39
|
* @returns The list of tweets that match the given filter
|
|
37
40
|
* @param filter The filter be used for searching the tweets
|
|
38
|
-
* @param count The number of tweets to fetch
|
|
41
|
+
* @param count The number of tweets to fetch, must be >= 1 and <= 100
|
|
39
42
|
* @param cursor The cursor to the next batch of tweets. If blank, first batch is fetched
|
|
40
43
|
*/
|
|
41
44
|
async getTweets(filter: TweetFilter, count: number, cursor: string): Promise<CursoredData<Tweet>> {
|
|
45
|
+
// If invalid count provided
|
|
46
|
+
if (count < 1 && !cursor) {
|
|
47
|
+
throw new Error(Errors.ValidationErrors.InvalidCount);
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
// Getting the raw data
|
|
43
|
-
let res = await this.request<RawTweets>(
|
|
51
|
+
let res = await this.request<RawTweets>(TweetUrls.tweetsUrl(toQueryString(filter), count, cursor), false).then(res => res.data);
|
|
44
52
|
|
|
45
53
|
// Extracting data
|
|
46
|
-
let data =
|
|
54
|
+
let data = TweetExtractors.extractTweets(res);
|
|
47
55
|
|
|
48
56
|
// Caching data
|
|
49
57
|
this.cacheData(data);
|
|
50
58
|
|
|
51
59
|
// Parsing data
|
|
52
|
-
let tweets = data.required.map(item =>
|
|
60
|
+
let tweets = data.required.map((item: TweetData) => TweetDeserializers.toTweet(item));
|
|
53
61
|
|
|
54
62
|
return {
|
|
55
63
|
list: tweets,
|
|
@@ -69,47 +77,50 @@ export class TweetService extends FetcherService {
|
|
|
69
77
|
if (cachedData) {
|
|
70
78
|
return cachedData;
|
|
71
79
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
let res = await this.request<RawTweet>(Urls.tweetDetailsUrl(tweetId), false).then(res => res.data);
|
|
80
|
+
|
|
81
|
+
// Fetching the raw data
|
|
82
|
+
let res = await this.request<RawTweet>(TweetUrls.tweetDetailsUrl(tweetId), false).then(res => res.data);
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
// Extracting data
|
|
85
|
+
let data = TweetExtractors.extractTweet(res, tweetId);
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
// Caching data
|
|
88
|
+
this.cacheData(data);
|
|
82
89
|
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
// Parsing data
|
|
91
|
+
let tweet = TweetDeserializers.toTweet(data.required[0]);
|
|
85
92
|
|
|
86
|
-
|
|
87
|
-
}
|
|
93
|
+
return tweet;
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
/**
|
|
91
97
|
* @returns The list of users who liked the given tweet
|
|
92
98
|
* @param tweetId The rest id of the target tweet
|
|
93
|
-
* @param count The batch size of the list
|
|
99
|
+
* @param count The batch size of the list, must be >= 10 (when no cursor is provided) and <= 100
|
|
94
100
|
* @param cursor The cursor to the next batch of users. If blank, first batch is fetched
|
|
95
101
|
*/
|
|
96
102
|
async getTweetLikers(tweetId: string, count: number, cursor: string): Promise<CursoredData<User>> {
|
|
97
103
|
// If user is not authenticated, abort
|
|
98
104
|
if(!this.isAuthenticated) {
|
|
99
|
-
|
|
105
|
+
throw new Error(Errors.AuthenticationErrors.NotAuthenticated);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// If invalid count provided
|
|
109
|
+
if (count < 10 && !cursor) {
|
|
110
|
+
throw new Error(Errors.ValidationErrors.InvalidCount);
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
// Fetching the raw data
|
|
103
|
-
let res = await this.request<RawLikers>(
|
|
114
|
+
let res = await this.request<RawLikers>(TweetUrls.tweetLikesUrl(tweetId, count, cursor)).then(res => res.data);
|
|
104
115
|
|
|
105
116
|
// Extracting data
|
|
106
|
-
let data =
|
|
117
|
+
let data = TweetExtractors.extractTweetLikers(res);
|
|
107
118
|
|
|
108
119
|
// Caching data
|
|
109
120
|
this.cacheData(data);
|
|
110
121
|
|
|
111
122
|
// Parsing data
|
|
112
|
-
let users = data.required.map(item =>
|
|
123
|
+
let users = data.required.map((item: UserData) => UserDeserializers.toUser(item));
|
|
113
124
|
|
|
114
125
|
return {
|
|
115
126
|
list: users,
|
|
@@ -120,26 +131,31 @@ export class TweetService extends FetcherService {
|
|
|
120
131
|
/**
|
|
121
132
|
* @returns The list of users who retweeted the given tweet
|
|
122
133
|
* @param tweetId The rest id of the target tweet
|
|
123
|
-
* @param count The batch size of the list
|
|
134
|
+
* @param count The batch size of the list, must be >= 10 (when no cursor is provided) and <= 100
|
|
124
135
|
* @param cursor The cursor to the next batch of users. If blank, first batch is fetched
|
|
125
136
|
*/
|
|
126
137
|
async getTweetRetweeters(tweetId: string, count: number, cursor: string): Promise<CursoredData<User>> {
|
|
127
138
|
// If user is not authenticated, abort
|
|
128
139
|
if(!this.isAuthenticated) {
|
|
129
|
-
|
|
140
|
+
throw new Error(Errors.AuthenticationErrors.NotAuthenticated);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// If invalid count provided
|
|
144
|
+
if (count < 10 && !cursor) {
|
|
145
|
+
throw new Error(Errors.ValidationErrors.InvalidCount);
|
|
130
146
|
}
|
|
131
147
|
|
|
132
148
|
// Fetching the raw data
|
|
133
|
-
let res = await this.request<RawRetweeters>(
|
|
149
|
+
let res = await this.request<RawRetweeters>(TweetUrls.tweetRetweetUrl(tweetId, count, cursor)).then(res => res.data);
|
|
134
150
|
|
|
135
151
|
// Extracting data
|
|
136
|
-
let data =
|
|
152
|
+
let data = TweetExtractors.extractTweetRetweeters(res);
|
|
137
153
|
|
|
138
154
|
// Caching data
|
|
139
155
|
this.cacheData(data);
|
|
140
156
|
|
|
141
157
|
// Parsing data
|
|
142
|
-
let users = data.required.map(item =>
|
|
158
|
+
let users = data.required.map((item: UserData) => UserDeserializers.toUser(item));
|
|
143
159
|
|
|
144
160
|
return {
|
|
145
161
|
list: users,
|
|
@@ -155,20 +171,20 @@ export class TweetService extends FetcherService {
|
|
|
155
171
|
async getTweetReplies(tweetId: string, cursor: string): Promise<CursoredData<Tweet>> {
|
|
156
172
|
// If user is not authenticated, abort
|
|
157
173
|
if(!this.isAuthenticated) {
|
|
158
|
-
|
|
174
|
+
throw new Error(Errors.AuthenticationErrors.NotAuthenticated);
|
|
159
175
|
}
|
|
160
176
|
|
|
161
177
|
// Fetching the raw data
|
|
162
|
-
let res = await this.request<RawTweet>(
|
|
178
|
+
let res = await this.request<RawTweet>(TweetUrls.tweetRepliesUrl(tweetId, cursor)).then(res => res.data);
|
|
163
179
|
|
|
164
180
|
// Extracting data
|
|
165
|
-
let data =
|
|
181
|
+
let data = TweetExtractors.extractTweetReplies(res, tweetId);
|
|
166
182
|
|
|
167
183
|
// Caching data
|
|
168
184
|
this.cacheData(data);
|
|
169
185
|
|
|
170
186
|
// Parsing data
|
|
171
|
-
let tweets = data.required.map(item =>
|
|
187
|
+
let tweets = data.required.map((item: TweetData) => TweetDeserializers.toTweet(item));
|
|
172
188
|
|
|
173
189
|
return {
|
|
174
190
|
list: tweets,
|