rettiwt-api 1.1.0 → 1.1.2
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/.github/workflows/build-docs.yml +27 -0
- package/README.md +3 -1
- package/dist/Test.d.ts +0 -0
- package/dist/Test.js +2 -0
- package/dist/Test.js.map +1 -0
- package/dist/index.d.ts +16 -5
- package/dist/index.js +22 -8
- package/dist/index.js.map +1 -1
- package/dist/models/graphql/Global.d.ts +4 -0
- package/dist/models/graphql/Global.js +13 -0
- package/dist/models/graphql/Global.js.map +1 -0
- package/dist/models/graphql/TweetTypes.d.ts +6 -0
- package/dist/models/graphql/TweetTypes.js +156 -0
- package/dist/models/graphql/TweetTypes.js.map +1 -0
- package/dist/models/graphql/UserTypes.d.ts +3 -0
- package/dist/models/graphql/UserTypes.js +139 -0
- package/dist/models/graphql/UserTypes.js.map +1 -0
- package/dist/queries/RootQuery.d.ts +4 -0
- package/dist/queries/RootQuery.js +70 -0
- package/dist/queries/RootQuery.js.map +1 -0
- package/dist/resolvers/AccountResolver.d.ts +12 -0
- package/dist/resolvers/AccountResolver.js +84 -0
- package/dist/resolvers/AccountResolver.js.map +1 -0
- package/dist/resolvers/ResolverBase.d.ts +5 -0
- package/dist/resolvers/ResolverBase.js +11 -0
- package/dist/resolvers/ResolverBase.js.map +1 -0
- package/dist/resolvers/TweetResolver.d.ts +54 -0
- package/dist/resolvers/TweetResolver.js +332 -0
- package/dist/resolvers/TweetResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts +38 -0
- package/dist/resolvers/UserResolver.js +253 -0
- package/dist/resolvers/UserResolver.js.map +1 -0
- package/dist/services/AuthService.d.ts +6 -2
- package/dist/services/AuthService.js +4 -3
- package/dist/services/AuthService.js.map +1 -1
- package/dist/services/CacheService.d.ts +12 -7
- package/dist/services/CacheService.js +12 -7
- package/dist/services/CacheService.js.map +1 -1
- package/dist/services/FetcherService.d.ts +32 -12
- package/dist/services/FetcherService.js +45 -14
- package/dist/services/FetcherService.js.map +1 -1
- package/dist/services/accounts/AccountService.d.ts +23 -6
- package/dist/services/accounts/AccountService.js +48 -9
- package/dist/services/accounts/AccountService.js.map +1 -1
- package/dist/services/data/TrendService.d.ts +17 -0
- package/dist/services/data/TrendService.js +116 -0
- package/dist/services/data/TrendService.js.map +1 -0
- package/dist/services/data/TweetService.d.ts +22 -15
- package/dist/services/data/TweetService.js +22 -15
- package/dist/services/data/TweetService.js.map +1 -1
- package/dist/services/data/UserAccountService.d.ts +42 -0
- package/dist/services/data/UserAccountService.js +239 -0
- package/dist/services/data/UserAccountService.js.map +1 -0
- package/dist/services/data/UserService.d.ts +21 -15
- package/dist/services/data/UserService.js +21 -15
- package/dist/services/data/UserService.js.map +1 -1
- package/dist/services/helper/Deserializers.d.ts +19 -0
- package/dist/services/helper/Deserializers.js +115 -0
- package/dist/services/helper/Deserializers.js.map +1 -0
- package/dist/services/helper/Extractors.d.ts +104 -0
- package/dist/services/helper/Extractors.js +432 -0
- package/dist/services/helper/Extractors.js.map +1 -0
- package/dist/services/helper/Urls.d.ts +85 -0
- package/dist/services/helper/Urls.js +130 -0
- package/dist/services/helper/Urls.js.map +1 -0
- package/dist/services/helper/extractors/Trends.d.ts +3 -0
- package/dist/services/helper/extractors/Trends.js +51 -0
- package/dist/services/helper/extractors/Trends.js.map +1 -0
- package/dist/services/helper/urls/Trends.d.ts +7 -0
- package/dist/services/helper/urls/Trends.js +13 -0
- package/dist/services/helper/urls/Trends.js.map +1 -0
- package/dist/types/Authentication.d.ts +27 -2
- package/dist/types/Authentication.js.map +1 -1
- package/dist/types/HTTP.d.ts +3 -1
- package/dist/types/HTTP.js +3 -1
- package/dist/types/HTTP.js.map +1 -1
- package/dist/types/Resolvers.d.ts +6 -1
- package/dist/types/Service.d.ts +30 -0
- package/dist/types/Service.js +19 -0
- package/dist/types/Service.js.map +1 -0
- package/dist/types/Trends.d.ts +50 -0
- package/dist/types/Trends.js +3 -0
- package/dist/types/Trends.js.map +1 -0
- package/dist/types/Tweet.d.ts +40 -0
- package/dist/types/Tweet.js +5 -0
- package/dist/types/Tweet.js.map +1 -0
- package/dist/types/UserAccount.d.ts +19 -0
- package/dist/types/UserAccount.js +4 -0
- package/dist/types/UserAccount.js.map +1 -0
- package/dist/types/data/Errors.d.ts +13 -4
- package/dist/types/data/Errors.js +12 -3
- package/dist/types/data/Errors.js.map +1 -1
- package/dist/types/data/Service.d.ts +19 -5
- package/dist/types/data/Service.js +6 -3
- package/dist/types/data/Service.js.map +1 -1
- package/dist/types/data/Tweet.d.ts +60 -3
- package/dist/types/data/Tweet.js +0 -1
- package/dist/types/data/Tweet.js.map +1 -1
- package/dist/types/data/User.d.ts +20 -1
- package/dist/types/data/User.js +0 -1
- package/dist/types/data/User.js.map +1 -1
- package/dist/types/graphql/Errors.d.ts +15 -0
- package/dist/types/graphql/Errors.js +23 -0
- package/dist/types/graphql/Errors.js.map +1 -0
- package/dist/types/raw/general/Trends.d.ts +324 -0
- package/dist/types/raw/general/Trends.js +3 -0
- package/dist/types/raw/general/Trends.js.map +1 -0
- package/dist/types/raw/user/Tweets.d.ts +2428 -0
- package/dist/types/raw/user/Tweets.js +3 -0
- package/dist/types/raw/user/Tweets.js.map +1 -0
- package/package.json +5 -4
- package/src/index.ts +19 -6
- package/src/services/AuthService.ts +13 -7
- package/src/services/CacheService.ts +12 -7
- package/src/services/FetcherService.ts +62 -21
- package/src/services/accounts/AccountService.ts +61 -12
- package/src/services/data/TweetService.ts +25 -18
- package/src/services/data/UserService.ts +21 -15
- package/src/types/Authentication.ts +27 -2
- package/src/types/HTTP.ts +4 -2
- package/src/types/Resolvers.ts +14 -6
- package/src/types/data/Errors.ts +13 -4
- package/src/types/data/Service.ts +28 -11
- package/src/types/data/Tweet.ts +109 -31
- package/src/types/data/User.ts +47 -17
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tweets.js","sourceRoot":"","sources":["../../../../src/types/raw/user/Tweets.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rettiwt-api",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
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!",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"bugs": {
|
|
22
22
|
"url": "https://github.com/Rishikant181/Rettiwt-API/issues"
|
|
23
23
|
},
|
|
24
|
-
"homepage": "https://github.
|
|
24
|
+
"homepage": "https://rishikant181.github.io/Rettiwt-API/",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"axios": "
|
|
26
|
+
"axios": "1.3.2",
|
|
27
27
|
"cookiejar": "2.1.4",
|
|
28
28
|
"express": "4.18.2",
|
|
29
29
|
"express-graphql": "0.12.0",
|
|
@@ -32,11 +32,12 @@
|
|
|
32
32
|
"node-libcurl": "3.0.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@types/cookiejar": "
|
|
35
|
+
"@types/cookiejar": "2.1.2",
|
|
36
36
|
"@types/express": "4.17.13",
|
|
37
37
|
"@types/graphql": "14.5.0",
|
|
38
38
|
"@types/node": "17.0.24",
|
|
39
39
|
"nodemon": "2.0.20",
|
|
40
|
+
"typedoc": "0.23.26",
|
|
40
41
|
"typescript": "4.6.4"
|
|
41
42
|
}
|
|
42
43
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,8 +5,11 @@ import { TweetService } from "./services/data/TweetService";
|
|
|
5
5
|
import { AccountService } from "./services/accounts/AccountService";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @param cookie The
|
|
8
|
+
* @param cookie The cookie string to use to fetch data
|
|
9
9
|
* @returns The API for fetching user and tweet data
|
|
10
|
+
* @remarks The cookie can be obtained by using {@link AccountService.login} method.
|
|
11
|
+
* To use the {@link AccountService.login} method, create a {@link Rettiwt} instance without passing any cookie string.
|
|
12
|
+
* Then use the {@link AccountService.login} method of {@link AccountService} to get the cookie.
|
|
10
13
|
*/
|
|
11
14
|
export const Rettiwt = (cookie: string = '') => {
|
|
12
15
|
// Creating new auth service instance using the given cookie string
|
|
@@ -20,8 +23,18 @@ export const Rettiwt = (cookie: string = '') => {
|
|
|
20
23
|
};
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
// Exporting
|
|
24
|
-
export
|
|
25
|
-
export
|
|
26
|
-
export
|
|
27
|
-
export
|
|
26
|
+
// Exporting classes
|
|
27
|
+
export * from './services/AuthService';
|
|
28
|
+
export * from './services/CacheService';
|
|
29
|
+
export * from './services/FetcherService';
|
|
30
|
+
export * from './services/accounts/AccountService';
|
|
31
|
+
export * from './services/data/TweetService';
|
|
32
|
+
export * from './services/data/UserService';
|
|
33
|
+
|
|
34
|
+
// Exporting types
|
|
35
|
+
export * from './types/data/Errors';
|
|
36
|
+
export * from './types/data/Service';
|
|
37
|
+
export * from './types/data/Tweet';
|
|
38
|
+
export * from './types/data/User';
|
|
39
|
+
export * from './types/Authentication';
|
|
40
|
+
export * from './types/HTTP';
|
|
@@ -11,13 +11,19 @@ import { GuestCredentials, AuthCredentials } from '../types/Authentication';
|
|
|
11
11
|
import { config } from '../config/env';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Handles authentication of http requests and other authentication related tasks.
|
|
15
|
+
* @internal
|
|
15
16
|
*/
|
|
16
17
|
export class AuthService {
|
|
17
18
|
// MEMBER DATA
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
19
|
+
/** The common bearer token for authentication. */
|
|
20
|
+
private authToken: string;
|
|
21
|
+
|
|
22
|
+
/** The current authentication credentials. */
|
|
23
|
+
private credentials: AuthCredentials;
|
|
24
|
+
|
|
25
|
+
/** Whether instance has been authenticated or not. */
|
|
26
|
+
public isAuthenticated: boolean;
|
|
21
27
|
|
|
22
28
|
// MEMBER METHODS
|
|
23
29
|
constructor(cookie: string = '') {
|
|
@@ -32,7 +38,7 @@ export class AuthService {
|
|
|
32
38
|
* The following regex pattern is used to extract the csrfToken from the cookie string.
|
|
33
39
|
* This is done by matching any string between the characters 'ct0=' and nearest enclosing ';'.
|
|
34
40
|
* (?<=pattern) starts matching after the given pattern.
|
|
35
|
-
* (?=pattern) stops matching just before the pattern
|
|
41
|
+
* (?=pattern) stops matching just before the pattern.
|
|
36
42
|
*/
|
|
37
43
|
this.credentials = { authToken: this.authToken, csrfToken: cookie.match(/(?<=ct0=).+?(?=;)/) + '', cookie: cookie};
|
|
38
44
|
|
|
@@ -46,7 +52,7 @@ export class AuthService {
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
49
|
-
* @returns The guest credentials fetched from twitter
|
|
55
|
+
* @returns The guest credentials fetched from twitter.
|
|
50
56
|
*/
|
|
51
57
|
async getGuestCredentials(): Promise<GuestCredentials> {
|
|
52
58
|
// Getting the guest credentials from twitter
|
|
@@ -59,4 +65,4 @@ export class AuthService {
|
|
|
59
65
|
guestToken: res.data.guest_token
|
|
60
66
|
}));
|
|
61
67
|
}
|
|
62
|
-
}
|
|
68
|
+
}
|
|
@@ -5,9 +5,12 @@ import NodeCache from 'node-cache';
|
|
|
5
5
|
import * as Parsers from './helper/Parser';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Handles reading and writing of data from and to cache.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* This services uses a local node-cache instance to cache data, since the data to be cached has no real purpose outside of the server session.
|
|
11
|
+
* This serivce follows a singleton pattern, where at any point, only a single instance of this class exists.
|
|
12
|
+
* This is done so that all the data is cached in a single instance, which makes sharing of cached data between different endpoints possible.
|
|
13
|
+
* @internal
|
|
11
14
|
*/
|
|
12
15
|
export class CacheService {
|
|
13
16
|
// MEMBER DATA
|
|
@@ -34,9 +37,11 @@ export class CacheService {
|
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @param data The input data to store
|
|
40
|
+
* Stores the input data in the cache.
|
|
41
|
+
*
|
|
42
|
+
* @param data The input data to store.
|
|
43
|
+
* @returns Whether writing to cache was successful or not.
|
|
44
|
+
* @remarks In order to cache data, the data to be cached must have a unique 'id' field.
|
|
40
45
|
*/
|
|
41
46
|
public write(data: any): void {
|
|
42
47
|
// Converting the data to a list of data
|
|
@@ -56,8 +61,8 @@ export class CacheService {
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
/**
|
|
59
|
-
* @
|
|
60
|
-
* @
|
|
64
|
+
* @param id The id id of the data to be fetched from cache.
|
|
65
|
+
* @returns The data with the given id.
|
|
61
66
|
*/
|
|
62
67
|
public read(id: string): any {
|
|
63
68
|
// Getting data from cache
|
|
@@ -17,7 +17,7 @@ import * as TweetDeserializers from './helper/deserializers/Tweets';
|
|
|
17
17
|
import { CurlyOptions } from 'node-libcurl/dist/curly';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* The different types of http requests.
|
|
21
21
|
*/
|
|
22
22
|
export enum HttpMethods {
|
|
23
23
|
POST = "POST",
|
|
@@ -25,15 +25,26 @@ export enum HttpMethods {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Handles all HTTP requests.
|
|
29
|
+
* @internal
|
|
30
|
+
*
|
|
31
|
+
* This serves as the base service from which all other data services derive their behaviour.
|
|
29
32
|
*/
|
|
30
33
|
export class FetcherService {
|
|
31
34
|
// MEMBER DATA
|
|
32
|
-
|
|
33
|
-
private
|
|
34
|
-
|
|
35
|
+
/** The authentication service instance. */
|
|
36
|
+
private auth: AuthService;
|
|
37
|
+
|
|
38
|
+
/** The caching service instance. */
|
|
39
|
+
private cache: CacheService;
|
|
40
|
+
|
|
41
|
+
/** Whether instance has been authenticated or not. */
|
|
42
|
+
protected isAuthenticated: boolean;
|
|
35
43
|
|
|
36
44
|
// MEMBER METHODS
|
|
45
|
+
/**
|
|
46
|
+
* @param auth The AuthService instance to use for authentication.
|
|
47
|
+
*/
|
|
37
48
|
constructor(auth: AuthService) {
|
|
38
49
|
this.auth = auth;
|
|
39
50
|
this.cache = CacheService.getInstance();
|
|
@@ -41,47 +52,75 @@ export class FetcherService {
|
|
|
41
52
|
}
|
|
42
53
|
|
|
43
54
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
55
|
+
* The middleware for handling any HTTP error.
|
|
56
|
+
*
|
|
57
|
+
* @param res The response object received.
|
|
58
|
+
* @throws {@link HttpStatus}.
|
|
59
|
+
* @returns The received response, if no HTTP errors are found.
|
|
46
60
|
*/
|
|
47
61
|
private handleHTTPError(res: CurlyResult): CurlyResult {
|
|
62
|
+
/**
|
|
63
|
+
* If the status code is not 200 => the HTTP request was not successful. hence throwing error
|
|
64
|
+
*/
|
|
48
65
|
if (res.statusCode != 200 && res.statusCode in HttpStatus) {
|
|
49
66
|
throw new Error(HttpStatus[res.statusCode])
|
|
50
67
|
}
|
|
51
|
-
|
|
68
|
+
|
|
52
69
|
return res;
|
|
53
70
|
}
|
|
54
71
|
|
|
55
72
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
73
|
+
* Creates an HTTP request according to the given parameters.
|
|
74
|
+
*
|
|
75
|
+
* This method internally uses node-libcurl library to make curl requests to the URL, instead of node-fetch.
|
|
76
|
+
* This has been done since that way it better mimics the HTTP requests made from browser.
|
|
77
|
+
*
|
|
78
|
+
* @param url The url to fetch data from.
|
|
79
|
+
* @param authenticate Whether to authenticate requests or not.
|
|
80
|
+
* @param method The HTTP method (from {@link HttpMethods}) to use.
|
|
81
|
+
* @param data The data to be sent along with the request (for POST request).
|
|
82
|
+
* @returns The {@link CurlyResult} received.
|
|
61
83
|
*/
|
|
62
84
|
protected async request<DataType>(url: string, authenticate: boolean = true, method: HttpMethods = HttpMethods.GET, data?: any): Promise<CurlyResult<DataType>> {
|
|
63
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Creating the request configuration based on the params
|
|
87
|
+
*/
|
|
64
88
|
let config: CurlyOptions = {
|
|
89
|
+
/**
|
|
90
|
+
* If authorization is required, using the authenticated header, using the authentication credentiials.
|
|
91
|
+
* Else, using the guest header, using the guest credentials.
|
|
92
|
+
*/
|
|
65
93
|
httpHeader: authenticate ? Headers.authorizedHeader(await this.auth.getAuthCredentials()) : Headers.guestHeader(await this.auth.getGuestCredentials()),
|
|
94
|
+
/**
|
|
95
|
+
* Disabling SSL peer verification because verification causes Error 404 (only while fetching tweets), likely because peer verification fails.
|
|
96
|
+
*/
|
|
66
97
|
sslVerifyPeer: false,
|
|
67
98
|
};
|
|
68
99
|
|
|
69
|
-
|
|
100
|
+
/**
|
|
101
|
+
* While making requests, if data is to be sent, the JSON data first need to be stringified.
|
|
102
|
+
* After making the request, the response is then passed to HTTP error handling middlware for HTTP error handling.
|
|
103
|
+
*/
|
|
104
|
+
// If POST request is to be made
|
|
70
105
|
if (method == HttpMethods.POST) {
|
|
71
106
|
return await curly.post(url, { ...config, postFields: JSON.stringify(data) }).then(res => this.handleHTTPError(res));
|
|
72
107
|
}
|
|
73
|
-
// If
|
|
108
|
+
// If GET request is to be made
|
|
74
109
|
else {
|
|
75
110
|
return await curly.get(url, config).then(res => this.handleHTTPError(res));
|
|
76
111
|
}
|
|
77
112
|
}
|
|
78
113
|
|
|
79
114
|
/**
|
|
80
|
-
*
|
|
115
|
+
* Caches the extracted data into the {@link CacheService} instance.
|
|
116
|
+
*
|
|
81
117
|
* @param data The extracted data to be cached
|
|
82
118
|
*/
|
|
83
119
|
protected cacheData(data: any): void {
|
|
84
|
-
|
|
120
|
+
/**
|
|
121
|
+
* The extracted data is in raw form.
|
|
122
|
+
* This raw data is deserialized into the respective known types.
|
|
123
|
+
*/
|
|
85
124
|
let users = data.users.map((user: RawUser) => UserDeserializers.toUser(user));
|
|
86
125
|
let tweets = data.tweets.map((tweet: RawTweet) => TweetDeserializers.toTweet(tweet));
|
|
87
126
|
|
|
@@ -91,11 +130,13 @@ export class FetcherService {
|
|
|
91
130
|
}
|
|
92
131
|
|
|
93
132
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
133
|
+
* Fetches the data with the given id from the cache.
|
|
134
|
+
*
|
|
135
|
+
* @param id The id of the data to be read from cache.
|
|
136
|
+
* @returns The data with the given id. If does not exists, returns undefined.
|
|
96
137
|
*/
|
|
97
138
|
protected readData(id: string): any {
|
|
98
139
|
// Reading data from cache
|
|
99
140
|
return this.cache.read(id);
|
|
100
141
|
}
|
|
101
|
-
}
|
|
142
|
+
}
|
|
@@ -6,18 +6,31 @@ import { AuthService } from '../AuthService';
|
|
|
6
6
|
|
|
7
7
|
// TYPES
|
|
8
8
|
import { GuestCredentials } from '../../types/Authentication';
|
|
9
|
+
import { HttpStatus } from '../../types/HTTP';
|
|
10
|
+
import { AuthenticationErrors } from '../../types/data/Errors';
|
|
9
11
|
|
|
10
12
|
// HELPERS
|
|
11
13
|
import LoginFlows from './LoginFlows';
|
|
12
14
|
import { loginHeader } from '../helper/Headers';
|
|
13
15
|
import { Cookie, CookieJar } from 'cookiejar';
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Handles all operations related to a user's account, such as loggin in, managing account, etc
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
15
21
|
export class AccountService {
|
|
16
22
|
// MEMBER DATA
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
/** The AuthService instance to use for authentication. */
|
|
24
|
+
private auth: AuthService;
|
|
25
|
+
|
|
26
|
+
/** The current guest credentials to use. */
|
|
27
|
+
private guestCreds: GuestCredentials;
|
|
28
|
+
|
|
29
|
+
/** The cookies received from Twitter after logging in. */
|
|
30
|
+
private cookies: Cookie[];
|
|
31
|
+
|
|
32
|
+
/** The flow token received after execution of current flow. */
|
|
33
|
+
private flowToken: string;
|
|
21
34
|
|
|
22
35
|
// MEMBER METHODS
|
|
23
36
|
constructor() {
|
|
@@ -40,7 +53,8 @@ export class AccountService {
|
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
/**
|
|
43
|
-
*
|
|
56
|
+
* Step 1: Initiates login
|
|
57
|
+
* @internal
|
|
44
58
|
*/
|
|
45
59
|
private async initiateLogin(): Promise<void> {
|
|
46
60
|
// Initiating the login process
|
|
@@ -58,7 +72,8 @@ export class AccountService {
|
|
|
58
72
|
}
|
|
59
73
|
|
|
60
74
|
/**
|
|
61
|
-
*
|
|
75
|
+
* Step 2: Does something
|
|
76
|
+
* @internal
|
|
62
77
|
*/
|
|
63
78
|
private async jsInstrumentationSubtask(): Promise<void> {
|
|
64
79
|
// Executing the flow
|
|
@@ -73,7 +88,10 @@ export class AccountService {
|
|
|
73
88
|
}
|
|
74
89
|
|
|
75
90
|
/**
|
|
76
|
-
*
|
|
91
|
+
* Step 3: Takes the email for login
|
|
92
|
+
* @internal
|
|
93
|
+
*
|
|
94
|
+
* @throws {@link AuthenticationErrors.InvalidEmail}, if email does not exist.
|
|
77
95
|
*/
|
|
78
96
|
private async enterUserIdentifier(email: string): Promise<void> {
|
|
79
97
|
// Executing the flow
|
|
@@ -83,12 +101,20 @@ export class AccountService {
|
|
|
83
101
|
postFields: JSON.stringify(LoginFlows.EnterUserIdentifier.body(this.flowToken, email))
|
|
84
102
|
});
|
|
85
103
|
|
|
104
|
+
// If no account found with given email
|
|
105
|
+
if (res.statusCode == HttpStatus.BadRequest && res.data.errors[0].code == 399) {
|
|
106
|
+
throw new Error(AuthenticationErrors.InvalidEmail);
|
|
107
|
+
}
|
|
108
|
+
|
|
86
109
|
// Getting the flow token
|
|
87
110
|
this.flowToken = res.data['flow_token'];
|
|
88
111
|
}
|
|
89
112
|
|
|
90
113
|
/**
|
|
91
|
-
*
|
|
114
|
+
* Step 4: Takes the username for login
|
|
115
|
+
* @internal
|
|
116
|
+
*
|
|
117
|
+
* @throws {@link AuthenticationErrors.InvalidUsername}, if wrong username entered.
|
|
92
118
|
*/
|
|
93
119
|
private async enterAlternateUserIdentifier(userName: string): Promise<void> {
|
|
94
120
|
// Executing the flow
|
|
@@ -98,12 +124,20 @@ export class AccountService {
|
|
|
98
124
|
postFields: JSON.stringify(LoginFlows.EnterAlternateUserIdentifier.body(this.flowToken, userName))
|
|
99
125
|
});
|
|
100
126
|
|
|
127
|
+
// If invalid username for the given account
|
|
128
|
+
if (res.statusCode == HttpStatus.BadRequest && res.data.errors[0].code == 399) {
|
|
129
|
+
throw new Error(AuthenticationErrors.InvalidUsername);
|
|
130
|
+
}
|
|
131
|
+
|
|
101
132
|
// Getting the flow token
|
|
102
133
|
this.flowToken = res.data['flow_token'];
|
|
103
134
|
}
|
|
104
135
|
|
|
105
136
|
/**
|
|
106
|
-
*
|
|
137
|
+
* Step 5: Takes the password for login
|
|
138
|
+
* @internal
|
|
139
|
+
*
|
|
140
|
+
* @throws {@link AuthenticationErrors.InvalidPassword}, incorrect password entered.
|
|
107
141
|
*/
|
|
108
142
|
private async enterPassword(password: string): Promise<void> {
|
|
109
143
|
// Executing the flow
|
|
@@ -113,12 +147,18 @@ export class AccountService {
|
|
|
113
147
|
postFields: JSON.stringify(LoginFlows.EnterPassword.body(this.flowToken, password))
|
|
114
148
|
});
|
|
115
149
|
|
|
150
|
+
// If invalid password for the given account
|
|
151
|
+
if (res.statusCode == HttpStatus.BadRequest && res.data.errors[0].code == 399) {
|
|
152
|
+
throw new Error(AuthenticationErrors.InvalidPassword);
|
|
153
|
+
}
|
|
154
|
+
|
|
116
155
|
// Getting the flow token
|
|
117
156
|
this.flowToken = res.data['flow_token'];
|
|
118
157
|
}
|
|
119
158
|
|
|
120
159
|
/**
|
|
121
|
-
*
|
|
160
|
+
* Step 6: Gets the actual cookies
|
|
161
|
+
* @internal
|
|
122
162
|
*/
|
|
123
163
|
private async accountDuplicationCheck(): Promise<void> {
|
|
124
164
|
// Executing the flow
|
|
@@ -128,7 +168,7 @@ export class AccountService {
|
|
|
128
168
|
postFields: JSON.stringify(LoginFlows.AccountDuplicationCheck.body(this.flowToken))
|
|
129
169
|
});
|
|
130
170
|
|
|
131
|
-
//
|
|
171
|
+
// Getting the cookies from the set-cookie header of the reponse.
|
|
132
172
|
this.cookies = new CookieJar().setCookies(res.headers[0]['Set-Cookie'] as string[]);
|
|
133
173
|
|
|
134
174
|
// Getting the flow token
|
|
@@ -136,13 +176,22 @@ export class AccountService {
|
|
|
136
176
|
}
|
|
137
177
|
|
|
138
178
|
/**
|
|
179
|
+
* Login to Twitter using the given credentials and get back the cookies.
|
|
180
|
+
* @public
|
|
181
|
+
*
|
|
139
182
|
* @param email The email of the account to be logged into
|
|
140
183
|
* @param userName The username associated with the given account
|
|
141
184
|
* @param password The password to the account
|
|
142
185
|
* @returns The cookies for authenticating with the given account
|
|
143
186
|
*/
|
|
144
187
|
public async login(email: string, userName: string, password: string): Promise<string> {
|
|
145
|
-
|
|
188
|
+
/**
|
|
189
|
+
* This works by sending a chain of request that are required for login to twitter.
|
|
190
|
+
* Each method in the chain returns a flow token that must be provied as payload in the next method in the chain.
|
|
191
|
+
* Each such method is called a subtask.
|
|
192
|
+
* Each subtask sets the {@link flowToken} property of the class which is then given in the payload of the next subtask.
|
|
193
|
+
* The final subtask returns the headers which actually contains the cookie in the 'set-cookie' field.
|
|
194
|
+
*/
|
|
146
195
|
await this.initiateLogin();
|
|
147
196
|
await this.jsInstrumentationSubtask();
|
|
148
197
|
await this.enterUserIdentifier(email);
|
|
@@ -27,19 +27,24 @@ import * as TweetDeserializers from '../helper/deserializers/Tweets';
|
|
|
27
27
|
import { toQueryString } from '../helper/Parser';
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* Handles fetching of data related to tweets.
|
|
31
|
+
* @public
|
|
31
32
|
*/
|
|
32
33
|
export class TweetService extends FetcherService {
|
|
33
34
|
// MEMBER METHODS
|
|
35
|
+
/**
|
|
36
|
+
* @param auth The AuthService instance to use for authentication.
|
|
37
|
+
*/
|
|
34
38
|
constructor(auth: AuthService) {
|
|
35
39
|
super(auth);
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
|
-
* @
|
|
40
|
-
* @param
|
|
41
|
-
* @param
|
|
42
|
-
* @
|
|
43
|
+
* @param filter The filter be used for searching the tweets.
|
|
44
|
+
* @param count The number of tweets to fetch.
|
|
45
|
+
* @param cursor The cursor to the next batch of tweets. If blank, first batch is fetched.
|
|
46
|
+
* @returns The list of tweets that match the given filter.
|
|
47
|
+
* @remarks count must be >= 1 and <= 100.
|
|
43
48
|
*/
|
|
44
49
|
async getTweets(filter: TweetFilter, count: number, cursor: string): Promise<CursoredData<Tweet>> {
|
|
45
50
|
// If invalid count provided
|
|
@@ -66,8 +71,8 @@ export class TweetService extends FetcherService {
|
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
/**
|
|
69
|
-
* @
|
|
70
|
-
* @
|
|
74
|
+
* @param tweetId The rest id of the target tweet.
|
|
75
|
+
* @returns The details of a single tweet with the given tweet id.
|
|
71
76
|
*/
|
|
72
77
|
async getTweetById(tweetId: string): Promise<Tweet> {
|
|
73
78
|
// Getting data from cache
|
|
@@ -94,10 +99,11 @@ export class TweetService extends FetcherService {
|
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
/**
|
|
97
|
-
* @
|
|
98
|
-
* @param
|
|
99
|
-
* @param
|
|
100
|
-
* @
|
|
102
|
+
* @param tweetId The rest id of the target tweet.
|
|
103
|
+
* @param count The batch size of the list.
|
|
104
|
+
* @param cursor The cursor to the next batch of users. If blank, first batch is fetched.
|
|
105
|
+
* @returns The list of users who liked the given tweet.
|
|
106
|
+
* @remarks count must be >= 10 (when no cursor is provided) and <= 100.
|
|
101
107
|
*/
|
|
102
108
|
async getTweetLikers(tweetId: string, count: number, cursor: string): Promise<CursoredData<User>> {
|
|
103
109
|
// If user is not authenticated, abort
|
|
@@ -129,10 +135,11 @@ export class TweetService extends FetcherService {
|
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
/**
|
|
132
|
-
* @
|
|
133
|
-
* @param
|
|
134
|
-
* @param
|
|
135
|
-
* @
|
|
138
|
+
* @param tweetId The rest id of the target tweet.
|
|
139
|
+
* @param count The batch size of the list.
|
|
140
|
+
* @param cursor The cursor to the next batch of users. If blank, first batch is fetched.
|
|
141
|
+
* @returns The list of users who retweeted the given tweet.
|
|
142
|
+
* @remarks count must be >= 10 (when no cursor is provided) and <= 100.
|
|
136
143
|
*/
|
|
137
144
|
async getTweetRetweeters(tweetId: string, count: number, cursor: string): Promise<CursoredData<User>> {
|
|
138
145
|
// If user is not authenticated, abort
|
|
@@ -167,9 +174,9 @@ export class TweetService extends FetcherService {
|
|
|
167
174
|
* THIS IS DISABLED FOR USE FOR NOW BECAUSE TWITTER DOESN'T HAVE ANY ENDPOINT FOR FETCHING REPLIES.
|
|
168
175
|
* THE DATA THIS RETURNS IS INCONSISTENT!
|
|
169
176
|
*
|
|
170
|
-
* @
|
|
171
|
-
* @param
|
|
172
|
-
* @
|
|
177
|
+
* @param tweetId The rest id of the target tweet.
|
|
178
|
+
* @param cursor The cursor to the next batch of replies. If blank, first batch is fetched.
|
|
179
|
+
* @returns The list of replies to the given tweet.
|
|
173
180
|
*/
|
|
174
181
|
/*
|
|
175
182
|
async getTweetReplies(tweetId: string, cursor: string): Promise<CursoredData<Tweet>> {
|
|
@@ -24,17 +24,20 @@ import * as UserDeserializers from '../helper/deserializers/Users';
|
|
|
24
24
|
import * as TweetDeserializers from '../helper/deserializers/Tweets';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Handles fetching of data related to user account
|
|
28
28
|
*/
|
|
29
29
|
export class UserService extends FetcherService {
|
|
30
30
|
// MEMBER METHODS
|
|
31
|
+
/**
|
|
32
|
+
* @param auth The AuthService instance to use for authentication.
|
|
33
|
+
*/
|
|
31
34
|
constructor(auth: AuthService) {
|
|
32
35
|
super(auth);
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
/**
|
|
36
|
-
* @returns The details of the given user
|
|
37
39
|
* @param screenName The screen name of the target user.
|
|
40
|
+
* @returns The details of the given user.
|
|
38
41
|
*/
|
|
39
42
|
async getUserDetails(screenName: string): Promise<User> {
|
|
40
43
|
// Fetching the raw data
|
|
@@ -53,8 +56,8 @@ export class UserService extends FetcherService {
|
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
/**
|
|
56
|
-
* @returns The details of the user with given rest id
|
|
57
59
|
* @param restId The screen name of the target user.
|
|
60
|
+
* @returns The details of the user with given rest id.
|
|
58
61
|
*/
|
|
59
62
|
async getUserDetailsById(restId: string): Promise<User> {
|
|
60
63
|
// Getting data from cache
|
|
@@ -81,10 +84,11 @@ export class UserService extends FetcherService {
|
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
/**
|
|
84
|
-
* @
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
87
|
-
* @
|
|
87
|
+
* @param userId The rest id of the target user.
|
|
88
|
+
* @param count The number of following to fetch.
|
|
89
|
+
* @param cursor The cursor to next batch. If blank, first batch is fetched.
|
|
90
|
+
* @returns The list of users followed by the target user.
|
|
91
|
+
* @remarks count must be >= 40 (when no cursor is provided) and <=100.
|
|
88
92
|
*/
|
|
89
93
|
async getUserFollowing(userId: string, count: number, cursor: string): Promise<CursoredData<User>> {
|
|
90
94
|
// If user is not authenticated, abort
|
|
@@ -116,10 +120,11 @@ export class UserService extends FetcherService {
|
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
/**
|
|
119
|
-
* @
|
|
120
|
-
* @param
|
|
121
|
-
* @param
|
|
122
|
-
* @
|
|
123
|
+
* @param userId The rest id of the target user.
|
|
124
|
+
* @param count The number of followers to fetch.
|
|
125
|
+
* @param cursor The cursor to next batch. If blank, first batch is fetched.
|
|
126
|
+
* @returns The list of users following the target user.
|
|
127
|
+
* @remarks count must be >= 40 (when no cursor is provided) and <=100.
|
|
123
128
|
*/
|
|
124
129
|
async getUserFollowers(userId: string, count: number, cursor: string): Promise<CursoredData<User>> {
|
|
125
130
|
// If user is not authenticated, abort
|
|
@@ -151,10 +156,11 @@ export class UserService extends FetcherService {
|
|
|
151
156
|
}
|
|
152
157
|
|
|
153
158
|
/**
|
|
154
|
-
* @
|
|
155
|
-
* @param
|
|
156
|
-
* @param
|
|
157
|
-
* @
|
|
159
|
+
* @param userId The rest id of the target user.
|
|
160
|
+
* @param count The number of likes to fetch.
|
|
161
|
+
* @param cursor The cursor to next batch. If blank, first batch is fetched.
|
|
162
|
+
* @returns The list of tweets liked by the target user.
|
|
163
|
+
* @remarks count must be >= 40 (when no cursor is provided) and <= 100.
|
|
158
164
|
*/
|
|
159
165
|
async getUserLikes(userId: string, count: number, cursor: string): Promise<CursoredData<Tweet>> {
|
|
160
166
|
// If user is not authenticated, abort
|