rettiwt-api 2.7.0 → 3.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/.eslintrc.js +73 -5
- package/.tool-versions +1 -0
- package/README.md +87 -20
- package/dist/Rettiwt.js +0 -1
- package/dist/Rettiwt.js.map +1 -1
- package/dist/cli.js +2 -4
- package/dist/cli.js.map +1 -1
- package/dist/collections/Extractors.d.ts +10 -0
- package/dist/collections/Extractors.js +43 -0
- package/dist/collections/Extractors.js.map +1 -0
- package/dist/collections/Groups.d.ts +19 -0
- package/dist/collections/Groups.js +55 -0
- package/dist/collections/Groups.js.map +1 -0
- package/dist/collections/Requests.d.ts +12 -0
- package/dist/collections/Requests.js +46 -0
- package/dist/collections/Requests.js.map +1 -0
- package/dist/commands/Auth.d.ts +6 -0
- package/dist/commands/Auth.js +26 -8
- package/dist/commands/Auth.js.map +1 -1
- package/dist/commands/Tweet.js +237 -82
- package/dist/commands/Tweet.js.map +1 -1
- package/dist/commands/User.js +197 -36
- package/dist/commands/User.js.map +1 -1
- package/dist/enums/Api.d.ts +30 -0
- package/dist/enums/Api.js +32 -1
- package/dist/enums/Api.js.map +1 -1
- package/dist/enums/Data.d.ts +9 -0
- package/dist/enums/Data.js +14 -0
- package/dist/enums/Data.js.map +1 -0
- package/dist/enums/Http.d.ts +1 -1
- package/dist/enums/Http.js +1 -1
- package/dist/enums/Logging.d.ts +6 -5
- package/dist/enums/Logging.js +6 -5
- package/dist/enums/Logging.js.map +1 -1
- package/dist/enums/Resource.d.ts +33 -0
- package/dist/enums/Resource.js +42 -0
- package/dist/enums/Resource.js.map +1 -0
- package/dist/helper/CliUtils.d.ts +1 -1
- package/dist/helper/CliUtils.js.map +1 -1
- package/dist/index.d.ts +11 -9
- package/dist/index.js +11 -14
- package/dist/index.js.map +1 -1
- package/dist/models/args/FetchArgs.d.ts +129 -0
- package/dist/models/args/FetchArgs.js +263 -0
- package/dist/models/args/FetchArgs.js.map +1 -0
- package/dist/models/args/PostArgs.d.ts +116 -0
- package/dist/models/args/PostArgs.js +232 -0
- package/dist/models/args/PostArgs.js.map +1 -0
- package/dist/models/data/CursoredData.d.ts +11 -11
- package/dist/models/data/CursoredData.js +21 -16
- package/dist/models/data/CursoredData.js.map +1 -1
- package/dist/models/data/List.d.ts +8 -10
- package/dist/models/data/List.js +2 -4
- package/dist/models/data/List.js.map +1 -1
- package/dist/models/data/Tweet.d.ts +41 -29
- package/dist/models/data/Tweet.js +71 -15
- package/dist/models/data/Tweet.js.map +1 -1
- package/dist/models/data/User.d.ts +36 -20
- package/dist/models/data/User.js +69 -7
- package/dist/models/data/User.js.map +1 -1
- package/dist/models/errors/ApiError.d.ts +1 -3
- package/dist/models/errors/ApiError.js +1 -4
- package/dist/models/errors/ApiError.js.map +1 -1
- package/dist/models/errors/DataValidationError.d.ts +30 -0
- package/dist/models/errors/DataValidationError.js +34 -0
- package/dist/models/errors/DataValidationError.js.map +1 -0
- package/dist/models/errors/HttpError.d.ts +1 -3
- package/dist/models/errors/HttpError.js +1 -4
- package/dist/models/errors/HttpError.js.map +1 -1
- package/dist/models/errors/TimeoutError.d.ts +2 -4
- package/dist/models/errors/TimeoutError.js +2 -5
- package/dist/models/errors/TimeoutError.js.map +1 -1
- package/dist/services/internal/ErrorService.d.ts +45 -35
- package/dist/services/internal/ErrorService.js +70 -68
- package/dist/services/internal/ErrorService.js.map +1 -1
- package/dist/services/internal/LogService.d.ts +7 -5
- package/dist/services/internal/LogService.js +28 -9
- package/dist/services/internal/LogService.js.map +1 -1
- package/dist/services/public/AuthService.d.ts +24 -20
- package/dist/services/public/AuthService.js +38 -36
- package/dist/services/public/AuthService.js.map +1 -1
- package/dist/services/public/FetcherService.d.ts +99 -0
- package/dist/services/public/FetcherService.js +254 -0
- package/dist/services/public/FetcherService.js.map +1 -0
- package/dist/services/public/TweetService.d.ts +213 -94
- package/dist/services/public/TweetService.js +405 -208
- package/dist/services/public/TweetService.js.map +1 -1
- package/dist/services/public/UserService.d.ts +185 -52
- package/dist/services/public/UserService.js +333 -103
- package/dist/services/public/UserService.js.map +1 -1
- package/dist/types/ReturnTypes.d.ts +21 -0
- package/dist/types/ReturnTypes.js +3 -0
- package/dist/types/ReturnTypes.js.map +1 -0
- package/package.json +4 -2
- package/src/Rettiwt.ts +0 -3
- package/src/cli.ts +2 -4
- package/src/collections/Extractors.ts +63 -0
- package/src/collections/Groups.ts +54 -0
- package/src/collections/Requests.ts +52 -0
- package/src/commands/Auth.ts +19 -7
- package/src/commands/Tweet.ts +179 -91
- package/src/commands/User.ts +118 -25
- package/src/enums/Api.ts +31 -0
- package/src/enums/Data.ts +9 -0
- package/src/enums/Http.ts +1 -1
- package/src/enums/Logging.ts +6 -5
- package/src/enums/Resource.ts +40 -0
- package/src/helper/CliUtils.ts +1 -1
- package/src/index.ts +41 -14
- package/src/models/args/FetchArgs.ts +296 -0
- package/src/models/args/PostArgs.ts +263 -0
- package/src/models/data/CursoredData.ts +23 -15
- package/src/models/data/List.ts +12 -15
- package/src/models/data/Tweet.ts +105 -39
- package/src/models/data/User.ts +97 -30
- package/src/models/errors/ApiError.ts +1 -4
- package/src/models/errors/DataValidationError.ts +44 -0
- package/src/models/errors/HttpError.ts +1 -4
- package/src/models/errors/TimeoutError.ts +2 -5
- package/src/services/internal/ErrorService.ts +76 -75
- package/src/services/internal/LogService.ts +20 -10
- package/src/services/public/AuthService.ts +39 -38
- package/src/services/public/FetcherService.ts +230 -0
- package/src/services/public/TweetService.ts +381 -179
- package/src/services/public/UserService.ts +314 -86
- package/src/types/RettiwtConfig.ts +0 -1
- package/src/types/ReturnTypes.ts +24 -0
- package/dist/models/args/TweetArgs.d.ts +0 -44
- package/dist/models/args/TweetArgs.js +0 -82
- package/dist/models/args/TweetArgs.js.map +0 -1
- package/dist/models/data/Media.d.ts +0 -14
- package/dist/models/data/Media.js +0 -19
- package/dist/models/data/Media.js.map +0 -1
- package/dist/services/internal/FetcherService.d.ts +0 -106
- package/dist/services/internal/FetcherService.js +0 -365
- package/dist/services/internal/FetcherService.js.map +0 -1
- package/src/models/args/TweetArgs.ts +0 -98
- package/src/models/data/Media.ts +0 -19
- package/src/services/internal/FetcherService.ts +0 -365
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
// PACKAGES
|
|
2
|
-
import {
|
|
3
|
-
ArrayMaxSize,
|
|
4
|
-
IsArray,
|
|
5
|
-
IsNotEmpty,
|
|
6
|
-
IsNumberString,
|
|
7
|
-
IsObject,
|
|
8
|
-
IsOptional,
|
|
9
|
-
IsString,
|
|
10
|
-
MaxLength,
|
|
11
|
-
validateSync,
|
|
12
|
-
} from 'class-validator';
|
|
13
|
-
import { DataValidationError } from 'rettiwt-core';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* The arguments specifying the tweet to be posted.
|
|
17
|
-
*/
|
|
18
|
-
export class TweetArgs {
|
|
19
|
-
/**
|
|
20
|
-
* The text content of the tweet.
|
|
21
|
-
*
|
|
22
|
-
* @remarks Length must be \<= 280 characters.
|
|
23
|
-
*/
|
|
24
|
-
@IsNotEmpty()
|
|
25
|
-
@IsString()
|
|
26
|
-
@MaxLength(280)
|
|
27
|
-
public text: string;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* The media content of the tweet.
|
|
31
|
-
*
|
|
32
|
-
* @remarks Max number of media that can be posted is 4.
|
|
33
|
-
*/
|
|
34
|
-
@IsOptional()
|
|
35
|
-
@IsArray()
|
|
36
|
-
@ArrayMaxSize(4)
|
|
37
|
-
@IsObject({ each: true })
|
|
38
|
-
public media?: TweetMediaArgs[];
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @param tweet - The tweet arguments specifying the tweet.
|
|
42
|
-
*/
|
|
43
|
-
public constructor(tweet: TweetArgs) {
|
|
44
|
-
this.text = tweet.text;
|
|
45
|
-
this.media = tweet.media ? tweet.media.map((item) => new TweetMediaArgs(item)) : undefined;
|
|
46
|
-
|
|
47
|
-
// Validating this object
|
|
48
|
-
const validationResult = validateSync(this);
|
|
49
|
-
|
|
50
|
-
// If validation error occured
|
|
51
|
-
if (validationResult.length) {
|
|
52
|
-
throw new DataValidationError(validationResult);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The arguments specifying the media to be posted in a single tweet.
|
|
59
|
-
*
|
|
60
|
-
* @public
|
|
61
|
-
*/
|
|
62
|
-
export class TweetMediaArgs {
|
|
63
|
-
/**
|
|
64
|
-
* The path to the media file.
|
|
65
|
-
*
|
|
66
|
-
* @remarks The size of the media file must be \<= 5242880 bytes.
|
|
67
|
-
*/
|
|
68
|
-
@IsNotEmpty()
|
|
69
|
-
@IsString()
|
|
70
|
-
public path: string;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* The list of id of users to be tagged in the media.
|
|
74
|
-
*
|
|
75
|
-
* @remarks Max number of tags is 10.
|
|
76
|
-
*/
|
|
77
|
-
@IsOptional()
|
|
78
|
-
@IsArray()
|
|
79
|
-
@ArrayMaxSize(10)
|
|
80
|
-
@IsNumberString(undefined, { each: true })
|
|
81
|
-
public tags?: string[];
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* @param media - The media arguments specifying the media.
|
|
85
|
-
*/
|
|
86
|
-
public constructor(media: TweetMediaArgs) {
|
|
87
|
-
this.path = media.path;
|
|
88
|
-
this.tags = media.tags ?? [];
|
|
89
|
-
|
|
90
|
-
// Validating this object
|
|
91
|
-
const validationResult = validateSync(this);
|
|
92
|
-
|
|
93
|
-
// If validation error occured
|
|
94
|
-
if (validationResult.length) {
|
|
95
|
-
throw new DataValidationError(validationResult);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
package/src/models/data/Media.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// PACKAGES
|
|
2
|
-
import { IMediaUploadInitializeResponse } from 'rettiwt-core';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The details of a single media file.
|
|
6
|
-
*
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
export class Media {
|
|
10
|
-
/** The id of the media. */
|
|
11
|
-
public id: string;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param media - The raw media data.
|
|
15
|
-
*/
|
|
16
|
-
public constructor(media: IMediaUploadInitializeResponse) {
|
|
17
|
-
this.id = media.media_id_string;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
// PACKAGES
|
|
2
|
-
import {
|
|
3
|
-
Request,
|
|
4
|
-
FetchArgs,
|
|
5
|
-
PostArgs,
|
|
6
|
-
EResourceType,
|
|
7
|
-
ICursor as IRawCursor,
|
|
8
|
-
ITweet as IRawTweet,
|
|
9
|
-
IUser as IRawUser,
|
|
10
|
-
ITimelineTweet,
|
|
11
|
-
ITimelineUser,
|
|
12
|
-
IResponse,
|
|
13
|
-
EUploadSteps,
|
|
14
|
-
IMediaUploadInitializeResponse,
|
|
15
|
-
} from 'rettiwt-core';
|
|
16
|
-
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
17
|
-
import https, { Agent } from 'https';
|
|
18
|
-
import { AuthCredential, Auth } from 'rettiwt-auth';
|
|
19
|
-
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
20
|
-
|
|
21
|
-
// SERVICES
|
|
22
|
-
import { ErrorService } from './ErrorService';
|
|
23
|
-
import { LogService } from './LogService';
|
|
24
|
-
|
|
25
|
-
// TYPES
|
|
26
|
-
import { IRettiwtConfig } from '../../types/RettiwtConfig';
|
|
27
|
-
import { IErrorHandler } from '../../types/ErrorHandler';
|
|
28
|
-
|
|
29
|
-
// ENUMS
|
|
30
|
-
import { EApiErrors } from '../../enums/Api';
|
|
31
|
-
import { ELogActions } from '../../enums/Logging';
|
|
32
|
-
|
|
33
|
-
// MODELS
|
|
34
|
-
import { CursoredData } from '../../models/data/CursoredData';
|
|
35
|
-
import { Tweet } from '../../models/data/Tweet';
|
|
36
|
-
import { User } from '../../models/data/User';
|
|
37
|
-
|
|
38
|
-
// HELPERS
|
|
39
|
-
import { findByFilter } from '../../helper/JsonUtils';
|
|
40
|
-
import { statSync } from 'fs';
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* The base service that handles all HTTP requests.
|
|
44
|
-
*
|
|
45
|
-
* @internal
|
|
46
|
-
*/
|
|
47
|
-
export class FetcherService {
|
|
48
|
-
/** The credential to use for authenticating against Twitter API. */
|
|
49
|
-
private cred?: AuthCredential;
|
|
50
|
-
|
|
51
|
-
/** Whether the instance is authenticated or not. */
|
|
52
|
-
private readonly isAuthenticated: boolean;
|
|
53
|
-
|
|
54
|
-
/** The URL to the proxy server to use for authentication. */
|
|
55
|
-
protected readonly authProxyUrl?: URL;
|
|
56
|
-
|
|
57
|
-
/** The HTTPS Agent to use for requests to Twitter API. */
|
|
58
|
-
private readonly httpsAgent: Agent;
|
|
59
|
-
|
|
60
|
-
/** The max wait time for a response. */
|
|
61
|
-
private readonly timeout: number;
|
|
62
|
-
|
|
63
|
-
/** The log service instance to use to logging. */
|
|
64
|
-
private readonly logger: LogService;
|
|
65
|
-
|
|
66
|
-
/** The service used to handle HTTP and API errors */
|
|
67
|
-
private readonly errorHandler: IErrorHandler;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @param config - The config object for configuring the Rettiwt instance.
|
|
71
|
-
*/
|
|
72
|
-
public constructor(config?: IRettiwtConfig) {
|
|
73
|
-
// If API key is supplied
|
|
74
|
-
if (config?.apiKey) {
|
|
75
|
-
this.cred = this.getAuthCredential(config.apiKey);
|
|
76
|
-
}
|
|
77
|
-
// If guest key is supplied
|
|
78
|
-
else if (config?.guestKey) {
|
|
79
|
-
this.cred = this.getGuestCredential(config.guestKey);
|
|
80
|
-
}
|
|
81
|
-
// If no key is supplied
|
|
82
|
-
else {
|
|
83
|
-
this.cred = undefined;
|
|
84
|
-
}
|
|
85
|
-
this.isAuthenticated = config?.apiKey ? true : false;
|
|
86
|
-
this.authProxyUrl = config?.authProxyUrl ?? config?.proxyUrl;
|
|
87
|
-
this.httpsAgent = this.getHttpsAgent(config?.proxyUrl);
|
|
88
|
-
this.timeout = config?.timeout ?? 0;
|
|
89
|
-
this.logger = new LogService(config?.logging);
|
|
90
|
-
this.errorHandler = config?.errorHandler ?? new ErrorService();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Returns an AuthCredential generated using the given API key.
|
|
95
|
-
*
|
|
96
|
-
* @param apiKey - The API key to use for authenticating.
|
|
97
|
-
* @returns The generated AuthCredential.
|
|
98
|
-
*/
|
|
99
|
-
private getAuthCredential(apiKey: string): AuthCredential {
|
|
100
|
-
// Converting apiKey from base64 to string
|
|
101
|
-
apiKey = Buffer.from(apiKey, 'base64').toString('ascii');
|
|
102
|
-
|
|
103
|
-
return new AuthCredential(apiKey.split(';'));
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Returns an AuthCredential generated using the given guest key.
|
|
108
|
-
*
|
|
109
|
-
* @param guestKey - The guest key to use for authenticating as guest.
|
|
110
|
-
* @returns The generated AuthCredential.
|
|
111
|
-
*/
|
|
112
|
-
private getGuestCredential(guestKey: string): AuthCredential {
|
|
113
|
-
return new AuthCredential(undefined, guestKey);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Checks the authorization status based on the requested resource.
|
|
118
|
-
*
|
|
119
|
-
* @param resourceType - The type of resource to fetch.
|
|
120
|
-
* @throws An error if not authorized to access the requested resource.
|
|
121
|
-
*/
|
|
122
|
-
private checkAuthorization(resourceType: EResourceType): void {
|
|
123
|
-
// Logging
|
|
124
|
-
this.logger.log(ELogActions.AUTHORIZATION, { authenticated: this.isAuthenticated });
|
|
125
|
-
|
|
126
|
-
// Checking authorization status
|
|
127
|
-
if (
|
|
128
|
-
resourceType != EResourceType.TWEET_DETAILS &&
|
|
129
|
-
resourceType != EResourceType.USER_DETAILS &&
|
|
130
|
-
resourceType != EResourceType.USER_TWEETS &&
|
|
131
|
-
this.isAuthenticated == false
|
|
132
|
-
) {
|
|
133
|
-
throw new Error(EApiErrors.RESOURCE_NOT_ALLOWED);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Gets the HttpsAgent based on whether a proxy is used or not.
|
|
139
|
-
*
|
|
140
|
-
* @param proxyUrl - Optional URL with proxy configuration to use for requests to Twitter API.
|
|
141
|
-
* @returns The HttpsAgent to use.
|
|
142
|
-
*/
|
|
143
|
-
private getHttpsAgent(proxyUrl?: URL): Agent {
|
|
144
|
-
if (proxyUrl) {
|
|
145
|
-
return new HttpsProxyAgent(proxyUrl);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return new https.Agent();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Makes an HTTP request according to the given parameters.
|
|
153
|
-
*
|
|
154
|
-
* @typeParam ResType - The type of the returned response data.
|
|
155
|
-
* @param config - The request configuration.
|
|
156
|
-
* @returns The response received.
|
|
157
|
-
*/
|
|
158
|
-
private async request<ResType>(config: AxiosRequestConfig): Promise<AxiosResponse<ResType>> {
|
|
159
|
-
// Checking authorization for the requested resource
|
|
160
|
-
this.checkAuthorization(config.url as EResourceType);
|
|
161
|
-
|
|
162
|
-
// If not authenticated, use guest authentication
|
|
163
|
-
this.cred = this.cred ?? (await new Auth({ proxyUrl: this.authProxyUrl }).getGuestCredential());
|
|
164
|
-
|
|
165
|
-
// Setting additional request parameters
|
|
166
|
-
config.headers = { ...config.headers, ...this.cred.toHeader() };
|
|
167
|
-
config.httpAgent = this.httpsAgent;
|
|
168
|
-
config.httpsAgent = this.httpsAgent;
|
|
169
|
-
config.timeout = this.timeout;
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* If Axios request results in an error, catch it and rethrow a more specific error.
|
|
173
|
-
*/
|
|
174
|
-
return await axios<ResType>(config).catch((error: unknown) => {
|
|
175
|
-
this.errorHandler.handle(error);
|
|
176
|
-
|
|
177
|
-
throw error;
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Extracts the required data based on the type of resource passed as argument.
|
|
183
|
-
*
|
|
184
|
-
* @param data - The data from which extraction is to be done.
|
|
185
|
-
* @param type - The type of data to extract.
|
|
186
|
-
* @returns The extracted data.
|
|
187
|
-
*/
|
|
188
|
-
private extractData(
|
|
189
|
-
data: NonNullable<unknown>,
|
|
190
|
-
type: EResourceType,
|
|
191
|
-
): {
|
|
192
|
-
/** The required extracted data. */
|
|
193
|
-
required: (IRawTweet | IRawUser)[];
|
|
194
|
-
|
|
195
|
-
/** The cursor string to the next batch of data. */
|
|
196
|
-
next: string;
|
|
197
|
-
} {
|
|
198
|
-
/**
|
|
199
|
-
* The required extracted data.
|
|
200
|
-
*/
|
|
201
|
-
let required: IRawTweet[] | IRawUser[] = [];
|
|
202
|
-
|
|
203
|
-
if (type == EResourceType.TWEET_DETAILS) {
|
|
204
|
-
required = findByFilter<IRawTweet>(data, '__typename', 'Tweet');
|
|
205
|
-
} else if (type == EResourceType.USER_DETAILS || type == EResourceType.USER_DETAILS_BY_ID) {
|
|
206
|
-
required = findByFilter<IRawUser>(data, '__typename', 'User');
|
|
207
|
-
} else if (
|
|
208
|
-
type == EResourceType.TWEET_SEARCH ||
|
|
209
|
-
type == EResourceType.USER_LIKES ||
|
|
210
|
-
type == EResourceType.LIST_TWEETS ||
|
|
211
|
-
type == EResourceType.USER_TWEETS ||
|
|
212
|
-
type == EResourceType.USER_TWEETS_AND_REPLIES
|
|
213
|
-
) {
|
|
214
|
-
required = findByFilter<ITimelineTweet>(data, '__typename', 'TimelineTweet').map(
|
|
215
|
-
(item) => item.tweet_results.result,
|
|
216
|
-
);
|
|
217
|
-
} else if (
|
|
218
|
-
type == EResourceType.TWEET_FAVORITERS ||
|
|
219
|
-
type == EResourceType.TWEET_RETWEETERS ||
|
|
220
|
-
type == EResourceType.USER_FOLLOWERS ||
|
|
221
|
-
type == EResourceType.USER_FOLLOWING
|
|
222
|
-
) {
|
|
223
|
-
required = findByFilter<ITimelineUser>(data, '__typename', 'TimelineUser').map(
|
|
224
|
-
(item) => item.user_results.result,
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return {
|
|
229
|
-
required: required,
|
|
230
|
-
next: findByFilter<IRawCursor>(data, 'cursorType', 'Bottom')[0]?.value,
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Deserializes the extracted data into a cursored list.
|
|
236
|
-
*
|
|
237
|
-
* @param extractedData - The list of extracted data.
|
|
238
|
-
* @param next - The cursor to the next batch of data.
|
|
239
|
-
* @returns The cursored data object.
|
|
240
|
-
*/
|
|
241
|
-
private deserializeData<OutType extends Tweet | User>(
|
|
242
|
-
extractedData: (IRawTweet | IRawUser)[] = [],
|
|
243
|
-
next: string = '',
|
|
244
|
-
): CursoredData<OutType> {
|
|
245
|
-
/** The list of deserialized data. */
|
|
246
|
-
const deserializedList: OutType[] = [];
|
|
247
|
-
|
|
248
|
-
// Deserializing the extracted raw data and storing it in the list
|
|
249
|
-
for (const item of extractedData) {
|
|
250
|
-
// If the item is a valid raw tweet
|
|
251
|
-
if (item && item.__typename == 'Tweet' && item.rest_id) {
|
|
252
|
-
// Logging
|
|
253
|
-
this.logger.log(ELogActions.DESERIALIZE, { type: item.__typename, id: item.rest_id });
|
|
254
|
-
|
|
255
|
-
// Adding deserialized Tweet to list
|
|
256
|
-
deserializedList.push(new Tweet(item as IRawTweet) as OutType);
|
|
257
|
-
}
|
|
258
|
-
// If the item is a valid raw user
|
|
259
|
-
else if (item && item.__typename == 'User' && item.rest_id && (item as IRawUser).id) {
|
|
260
|
-
// Logging
|
|
261
|
-
this.logger.log(ELogActions.DESERIALIZE, { type: item.__typename, id: item.rest_id });
|
|
262
|
-
|
|
263
|
-
// Adding deserialized User to list
|
|
264
|
-
deserializedList.push(new User(item as IRawUser) as OutType);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return new CursoredData<OutType>(deserializedList, next);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Fetches the requested resource from Twitter and returns it after processing.
|
|
273
|
-
*
|
|
274
|
-
* @param resourceType - The type of resource to fetch.
|
|
275
|
-
* @param args - Resource specific arguments.
|
|
276
|
-
* @typeParam OutType - The type of deserialized data returned.
|
|
277
|
-
* @returns The processed data requested from Twitter.
|
|
278
|
-
*/
|
|
279
|
-
protected async fetch<OutType extends Tweet | User>(
|
|
280
|
-
resourceType: EResourceType,
|
|
281
|
-
args: FetchArgs,
|
|
282
|
-
): Promise<CursoredData<OutType>> {
|
|
283
|
-
// Logging
|
|
284
|
-
this.logger.log(ELogActions.FETCH, { resourceType: resourceType, args: args });
|
|
285
|
-
|
|
286
|
-
// Preparing the HTTP request
|
|
287
|
-
const request: AxiosRequestConfig = new Request(resourceType, args).toAxiosRequestConfig();
|
|
288
|
-
|
|
289
|
-
// Getting the raw data
|
|
290
|
-
const res = await this.request<IResponse<unknown>>(request).then((res) => res.data);
|
|
291
|
-
|
|
292
|
-
// Extracting data
|
|
293
|
-
const extractedData = this.extractData(res, resourceType);
|
|
294
|
-
|
|
295
|
-
// Deserializing data
|
|
296
|
-
const deserializedData = this.deserializeData<OutType>(extractedData.required, extractedData.next);
|
|
297
|
-
|
|
298
|
-
return deserializedData;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Posts the requested resource to Twitter and returns the response.
|
|
303
|
-
*
|
|
304
|
-
* @param resourceType - The type of resource to post.
|
|
305
|
-
* @param args - Resource specific arguments.
|
|
306
|
-
* @returns Whether posting was successful or not.
|
|
307
|
-
*/
|
|
308
|
-
protected async post(resourceType: EResourceType, args: PostArgs): Promise<boolean> {
|
|
309
|
-
// Logging
|
|
310
|
-
this.logger.log(ELogActions.POST, { resourceType: resourceType, args: args });
|
|
311
|
-
|
|
312
|
-
// Preparing the HTTP request
|
|
313
|
-
const request: AxiosRequestConfig = new Request(resourceType, args).toAxiosRequestConfig();
|
|
314
|
-
|
|
315
|
-
// Posting the data
|
|
316
|
-
await this.request<unknown>(request);
|
|
317
|
-
|
|
318
|
-
return true;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Uploads the given media file to Twitter
|
|
323
|
-
*
|
|
324
|
-
* @param media - The path to the media file to upload.
|
|
325
|
-
* @returns The id of the uploaded media.
|
|
326
|
-
*/
|
|
327
|
-
protected async upload(media: string): Promise<string> {
|
|
328
|
-
// INITIALIZE
|
|
329
|
-
|
|
330
|
-
// Logging
|
|
331
|
-
this.logger.log(ELogActions.UPLOAD, { step: EUploadSteps.INITIALIZE });
|
|
332
|
-
|
|
333
|
-
const id: string = (
|
|
334
|
-
await this.request<IMediaUploadInitializeResponse>(
|
|
335
|
-
new Request(EResourceType.MEDIA_UPLOAD, {
|
|
336
|
-
upload: { step: EUploadSteps.INITIALIZE, size: statSync(media).size },
|
|
337
|
-
}).toAxiosRequestConfig(),
|
|
338
|
-
)
|
|
339
|
-
).data.media_id_string;
|
|
340
|
-
|
|
341
|
-
// APPEND
|
|
342
|
-
|
|
343
|
-
// Logging
|
|
344
|
-
this.logger.log(ELogActions.UPLOAD, { step: EUploadSteps.APPEND });
|
|
345
|
-
|
|
346
|
-
await this.request<unknown>(
|
|
347
|
-
new Request(EResourceType.MEDIA_UPLOAD, {
|
|
348
|
-
upload: { step: EUploadSteps.APPEND, id: id, media: media },
|
|
349
|
-
}).toAxiosRequestConfig(),
|
|
350
|
-
);
|
|
351
|
-
|
|
352
|
-
// FINALIZE
|
|
353
|
-
|
|
354
|
-
// Logging
|
|
355
|
-
this.logger.log(ELogActions.UPLOAD, { step: EUploadSteps.APPEND });
|
|
356
|
-
|
|
357
|
-
await this.request<unknown>(
|
|
358
|
-
new Request(EResourceType.MEDIA_UPLOAD, {
|
|
359
|
-
upload: { step: EUploadSteps.FINALIZE, id: id },
|
|
360
|
-
}).toAxiosRequestConfig(),
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
return id;
|
|
364
|
-
}
|
|
365
|
-
}
|