rettiwt-api 3.1.1 → 4.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/.github/FUNDING.yml +4 -0
- package/.github/workflows/documentation.yml +5 -0
- package/.github/workflows/publish.yml +3 -0
- package/.yarnrc.yml +1 -0
- package/README.md +50 -10
- package/dist/collections/Extractors.d.ts +4 -2
- package/dist/collections/Extractors.js +3 -3
- package/dist/collections/Extractors.js.map +1 -1
- package/dist/collections/Groups.js +3 -1
- package/dist/collections/Groups.js.map +1 -1
- package/dist/collections/Requests.js +3 -1
- package/dist/collections/Requests.js.map +1 -1
- package/dist/commands/Tweet.js +73 -41
- package/dist/commands/Tweet.js.map +1 -1
- package/dist/commands/User.js +3 -4
- package/dist/commands/User.js.map +1 -1
- package/dist/enums/Resource.d.ts +3 -1
- package/dist/enums/Resource.js +3 -1
- package/dist/enums/Resource.js.map +1 -1
- package/dist/helper/CliUtils.d.ts +2 -0
- package/dist/helper/CliUtils.js +2 -0
- package/dist/helper/CliUtils.js.map +1 -1
- package/dist/helper/JsonUtils.d.ts +2 -0
- package/dist/helper/JsonUtils.js +2 -0
- package/dist/helper/JsonUtils.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/models/args/FetchArgs.d.ts +0 -2
- package/dist/models/args/FetchArgs.js +126 -10
- package/dist/models/args/FetchArgs.js.map +1 -1
- package/dist/models/args/PostArgs.d.ts +3 -1
- package/dist/models/args/PostArgs.js +62 -24
- package/dist/models/args/PostArgs.js.map +1 -1
- package/dist/models/data/Tweet.d.ts +3 -3
- package/dist/models/data/Tweet.js +1 -1
- package/dist/models/data/Tweet.js.map +1 -1
- package/dist/services/public/AuthService.d.ts +21 -0
- package/dist/services/public/AuthService.js +44 -1
- package/dist/services/public/AuthService.js.map +1 -1
- package/dist/services/public/FetcherService.d.ts +2 -2
- package/dist/services/public/FetcherService.js +5 -6
- package/dist/services/public/FetcherService.js.map +1 -1
- package/dist/services/public/TweetService.d.ts +55 -32
- package/dist/services/public/TweetService.js +96 -55
- package/dist/services/public/TweetService.js.map +1 -1
- package/dist/services/public/UserService.d.ts +4 -5
- package/dist/services/public/UserService.js +5 -6
- package/dist/services/public/UserService.js.map +1 -1
- package/package.json +3 -2
- package/src/collections/Extractors.ts +6 -3
- package/src/collections/Groups.ts +3 -1
- package/src/collections/Requests.ts +3 -1
- package/src/commands/Tweet.ts +43 -18
- package/src/commands/User.ts +3 -4
- package/src/enums/Resource.ts +3 -1
- package/src/helper/CliUtils.ts +2 -0
- package/src/helper/JsonUtils.ts +2 -0
- package/src/index.ts +5 -1
- package/src/models/args/FetchArgs.ts +128 -11
- package/src/models/args/PostArgs.ts +65 -24
- package/src/models/data/Tweet.ts +4 -4
- package/src/services/public/AuthService.ts +51 -1
- package/src/services/public/FetcherService.ts +9 -8
- package/src/services/public/TweetService.ts +103 -60
- package/src/services/public/UserService.ts +5 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Auth } from 'rettiwt-auth';
|
|
2
2
|
|
|
3
|
+
import { EApiErrors } from '../../enums/Api';
|
|
3
4
|
import { IRettiwtConfig } from '../../types/RettiwtConfig';
|
|
4
5
|
|
|
5
6
|
import { FetcherService } from './FetcherService';
|
|
@@ -19,6 +20,55 @@ export class AuthService extends FetcherService {
|
|
|
19
20
|
super(config);
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Decodes the encoded cookie string.
|
|
25
|
+
*
|
|
26
|
+
* @param encodedCookies - The encoded cookie string to decode.
|
|
27
|
+
* @returns The decoded cookie string.
|
|
28
|
+
*/
|
|
29
|
+
public static decodeCookie(encodedCookies: string): string {
|
|
30
|
+
// Decoding the encoded cookie string
|
|
31
|
+
const decodedCookies: string = Buffer.from(encodedCookies, 'base64').toString('ascii');
|
|
32
|
+
|
|
33
|
+
return decodedCookies;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Encodes the given cookie string.
|
|
38
|
+
*
|
|
39
|
+
* @param cookieString - The cookie string to encode.
|
|
40
|
+
* @returns The encoded cookie string.
|
|
41
|
+
*/
|
|
42
|
+
public static encodeCookie(cookieString: string): string {
|
|
43
|
+
// Encoding the cookie string to base64
|
|
44
|
+
const encodedCookies: string = Buffer.from(cookieString).toString('base64');
|
|
45
|
+
|
|
46
|
+
return encodedCookies;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Gets the user's id from the given API key.
|
|
51
|
+
*
|
|
52
|
+
* @param apiKey - The API key.
|
|
53
|
+
* @returns The user id associated with the API key.
|
|
54
|
+
*/
|
|
55
|
+
public static getUserId(apiKey: string): string {
|
|
56
|
+
// Getting the cookie string from the API key
|
|
57
|
+
const cookieString: string = AuthService.decodeCookie(apiKey);
|
|
58
|
+
|
|
59
|
+
// Searching for the user id in the cookie string
|
|
60
|
+
const searchResults: string[] | null = cookieString.match(/((?<=twid="u=)(.*)(?="))|((?<=twid=u%3D)(.*)(?=;))/);
|
|
61
|
+
|
|
62
|
+
// If user id was found
|
|
63
|
+
if (searchResults) {
|
|
64
|
+
return searchResults[0];
|
|
65
|
+
}
|
|
66
|
+
// If user id was not found
|
|
67
|
+
else {
|
|
68
|
+
throw new Error(EApiErrors.BAD_AUTHENTICATION);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
22
72
|
/**
|
|
23
73
|
* Login to twitter as guest.
|
|
24
74
|
*
|
|
@@ -91,7 +141,7 @@ export class AuthService extends FetcherService {
|
|
|
91
141
|
).toHeader().cookie as string) ?? '';
|
|
92
142
|
|
|
93
143
|
// Converting the credentials to base64 string
|
|
94
|
-
apiKey =
|
|
144
|
+
apiKey = AuthService.encodeCookie(apiKey);
|
|
95
145
|
|
|
96
146
|
return apiKey;
|
|
97
147
|
}
|
|
@@ -17,6 +17,8 @@ import { IRettiwtConfig } from '../../types/RettiwtConfig';
|
|
|
17
17
|
import { ErrorService } from '../internal/ErrorService';
|
|
18
18
|
import { LogService } from '../internal/LogService';
|
|
19
19
|
|
|
20
|
+
import { AuthService } from './AuthService';
|
|
21
|
+
|
|
20
22
|
/**
|
|
21
23
|
* The base service that handles all HTTP requests.
|
|
22
24
|
*
|
|
@@ -32,9 +34,6 @@ export class FetcherService {
|
|
|
32
34
|
/** The guest key to use for authenticating against Twitter API as guest. */
|
|
33
35
|
private readonly guestKey?: string;
|
|
34
36
|
|
|
35
|
-
/** Whether the instance is authenticated or not. */
|
|
36
|
-
private readonly isAuthenticated: boolean;
|
|
37
|
-
|
|
38
37
|
/** The URL To the proxy server to use for all others. */
|
|
39
38
|
private readonly proxyUrl?: URL;
|
|
40
39
|
|
|
@@ -44,6 +43,9 @@ export class FetcherService {
|
|
|
44
43
|
/** The URL to the proxy server to use only for authentication. */
|
|
45
44
|
protected readonly authProxyUrl?: URL;
|
|
46
45
|
|
|
46
|
+
/** The id of the authenticated user (if any). */
|
|
47
|
+
protected readonly userId?: string;
|
|
48
|
+
|
|
47
49
|
/**
|
|
48
50
|
* @param config - The config object for configuring the Rettiwt instance.
|
|
49
51
|
*/
|
|
@@ -51,7 +53,7 @@ export class FetcherService {
|
|
|
51
53
|
LogService.enabled = config?.logging ?? false;
|
|
52
54
|
this.apiKey = config?.apiKey;
|
|
53
55
|
this.guestKey = config?.guestKey;
|
|
54
|
-
this.
|
|
56
|
+
this.userId = config?.apiKey ? AuthService.getUserId(config.apiKey) : undefined;
|
|
55
57
|
this.authProxyUrl = config?.authProxyUrl ?? config?.proxyUrl;
|
|
56
58
|
this.proxyUrl = config?.proxyUrl;
|
|
57
59
|
this.timeout = config?.timeout ?? 0;
|
|
@@ -67,10 +69,10 @@ export class FetcherService {
|
|
|
67
69
|
*/
|
|
68
70
|
private checkAuthorization(resource: EResourceType): void {
|
|
69
71
|
// Logging
|
|
70
|
-
LogService.log(ELogActions.AUTHORIZATION, { authenticated: this.
|
|
72
|
+
LogService.log(ELogActions.AUTHORIZATION, { authenticated: this.userId != undefined });
|
|
71
73
|
|
|
72
74
|
// Checking authorization status
|
|
73
|
-
if (!allowGuestAuthentication.includes(resource) && this.
|
|
75
|
+
if (!allowGuestAuthentication.includes(resource) && this.userId == undefined) {
|
|
74
76
|
throw new Error(EApiErrors.RESOURCE_NOT_ALLOWED);
|
|
75
77
|
}
|
|
76
78
|
}
|
|
@@ -85,8 +87,7 @@ export class FetcherService {
|
|
|
85
87
|
// Logging
|
|
86
88
|
LogService.log(ELogActions.GET, { target: 'USER_CREDENTIAL' });
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
return new AuthCredential(cookies);
|
|
90
|
+
return new AuthCredential(AuthService.decodeCookie(this.apiKey).split(';'));
|
|
90
91
|
} else if (this.guestKey) {
|
|
91
92
|
// Logging
|
|
92
93
|
LogService.log(ELogActions.GET, { target: 'GUEST_CREDENTIAL' });
|
|
@@ -5,14 +5,16 @@ import {
|
|
|
5
5
|
IListTweetsResponse,
|
|
6
6
|
ITweetDetailsResponse,
|
|
7
7
|
ITweetLikeResponse,
|
|
8
|
-
ITweetLikersResponse,
|
|
9
8
|
ITweetPostResponse,
|
|
9
|
+
ITweetRepliesResponse,
|
|
10
10
|
ITweetRetweetersResponse,
|
|
11
11
|
ITweetRetweetResponse,
|
|
12
|
+
ITweetScheduleResponse,
|
|
12
13
|
ITweetSearchResponse,
|
|
13
14
|
ITweetUnlikeResponse,
|
|
14
15
|
ITweetUnpostResponse,
|
|
15
16
|
ITweetUnretweetResponse,
|
|
17
|
+
ITweetUnscheduleResponse,
|
|
16
18
|
TweetFilter,
|
|
17
19
|
} from 'rettiwt-core';
|
|
18
20
|
|
|
@@ -68,15 +70,32 @@ export class TweetService extends FetcherService {
|
|
|
68
70
|
* ```
|
|
69
71
|
*/
|
|
70
72
|
public async details(id: string): Promise<Tweet | undefined> {
|
|
71
|
-
|
|
73
|
+
let resource: EResourceType;
|
|
72
74
|
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
+
// If user is authenticated
|
|
76
|
+
if (this.userId != undefined) {
|
|
77
|
+
resource = EResourceType.TWEET_DETAILS_ALT;
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
// Fetching raw tweet details
|
|
80
|
+
const response = await this.request<ITweetRepliesResponse>(resource, { id: id });
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
// Deserializing response
|
|
83
|
+
const data = extractors[resource](response, id);
|
|
84
|
+
|
|
85
|
+
return data;
|
|
86
|
+
}
|
|
87
|
+
// If user is not authenticated
|
|
88
|
+
else {
|
|
89
|
+
resource = EResourceType.TWEET_DETAILS;
|
|
90
|
+
|
|
91
|
+
// Fetching raw tweet details
|
|
92
|
+
const response = await this.request<ITweetDetailsResponse>(resource, { id: id });
|
|
93
|
+
|
|
94
|
+
// Deserializing response
|
|
95
|
+
const data = extractors[resource](response, id);
|
|
96
|
+
|
|
97
|
+
return data;
|
|
98
|
+
}
|
|
80
99
|
}
|
|
81
100
|
|
|
82
101
|
/**
|
|
@@ -117,58 +136,6 @@ export class TweetService extends FetcherService {
|
|
|
117
136
|
return data;
|
|
118
137
|
}
|
|
119
138
|
|
|
120
|
-
/**
|
|
121
|
-
* @deprecated
|
|
122
|
-
* The method will be removed in the next release following the removal of the ability to see tweet likers by Twitter.
|
|
123
|
-
* Currently, the method does not work.
|
|
124
|
-
*
|
|
125
|
-
* Get the list of users who liked a tweet.
|
|
126
|
-
*
|
|
127
|
-
* @param id - The id of the target tweet.
|
|
128
|
-
* @param count - The number of likers to fetch, must be \<= 100.
|
|
129
|
-
* @param cursor - The cursor to the batch of likers to fetch.
|
|
130
|
-
*
|
|
131
|
-
* @returns The list of users who liked the given tweet.
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* ```
|
|
135
|
-
* import { Rettiwt } from 'rettiwt-api';
|
|
136
|
-
*
|
|
137
|
-
* // Creating a new Rettiwt instance using the given 'API_KEY'
|
|
138
|
-
* const rettiwt = new Rettiwt({ apiKey: API_KEY });
|
|
139
|
-
*
|
|
140
|
-
* // Fetching the most recent 100 likers of the Tweet with id '1234567890'
|
|
141
|
-
* rettiwt.tweet.likers('1234567890')
|
|
142
|
-
* .then(res => {
|
|
143
|
-
* console.log(res);
|
|
144
|
-
* })
|
|
145
|
-
* .catch(err => {
|
|
146
|
-
* console.log(err);
|
|
147
|
-
* });
|
|
148
|
-
* ```
|
|
149
|
-
*/
|
|
150
|
-
public async likers(id: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
|
|
151
|
-
// Deprecation warning
|
|
152
|
-
console.log(`
|
|
153
|
-
This method has been deprecated following the removal of the ability to see tweet liksers by Twitter.
|
|
154
|
-
Currently, the method does not work.
|
|
155
|
-
`);
|
|
156
|
-
|
|
157
|
-
const resource = EResourceType.TWEET_LIKERS;
|
|
158
|
-
|
|
159
|
-
// Fetching raw likers
|
|
160
|
-
const response = await this.request<ITweetLikersResponse>(resource, {
|
|
161
|
-
id: id,
|
|
162
|
-
count: count,
|
|
163
|
-
cursor: cursor,
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// Deserializing response
|
|
167
|
-
const data = extractors[resource](response);
|
|
168
|
-
|
|
169
|
-
return data;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
139
|
/**
|
|
173
140
|
* Get the list of tweets from a tweet list.
|
|
174
141
|
*
|
|
@@ -221,7 +188,7 @@ export class TweetService extends FetcherService {
|
|
|
221
188
|
*
|
|
222
189
|
* @param options - The options describing the tweet to be posted. Check {@link TweetArgs} for available options.
|
|
223
190
|
*
|
|
224
|
-
* @returns
|
|
191
|
+
* @returns The id of the posted tweet.
|
|
225
192
|
*
|
|
226
193
|
* @example
|
|
227
194
|
* Posting a simple text
|
|
@@ -385,6 +352,46 @@ export class TweetService extends FetcherService {
|
|
|
385
352
|
return data;
|
|
386
353
|
}
|
|
387
354
|
|
|
355
|
+
/**
|
|
356
|
+
* Schedule a tweet.
|
|
357
|
+
*
|
|
358
|
+
* @param options - The options describing the tweet to be posted. Check {@link TweetArgs} for available options.
|
|
359
|
+
*
|
|
360
|
+
* @returns The id of the schedule.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* Scheduling a simple text
|
|
364
|
+
* ```
|
|
365
|
+
* import { Rettiwt } from 'rettiwt-api';
|
|
366
|
+
*
|
|
367
|
+
* // Creating a new Rettiwt instance using the given 'API_KEY'
|
|
368
|
+
* const rettiwt = new Rettiwt({ apiKey: API_KEY });
|
|
369
|
+
*
|
|
370
|
+
* // Scheduling a tweet to posted at 19th of August, 2024, at 11:59:00 AM, in local time
|
|
371
|
+
* rettiwt.tweet.schedule({ text: 'Hello World!', scheduleFor: new Date('2024-08-19 23:59:00') })
|
|
372
|
+
* .then(res => {
|
|
373
|
+
* console.log(res);
|
|
374
|
+
* })
|
|
375
|
+
* .catch(err => {
|
|
376
|
+
* console.log(err);
|
|
377
|
+
* });
|
|
378
|
+
* ```
|
|
379
|
+
*
|
|
380
|
+
* @remarks
|
|
381
|
+
* Scheduling a tweet is similar to {@link post}ing, except that an extra parameter called `scheduleFor` is used.
|
|
382
|
+
*/
|
|
383
|
+
public async schedule(options: TweetArgs): Promise<string | undefined> {
|
|
384
|
+
const resource = EResourceType.TWEET_SCHEDULE;
|
|
385
|
+
|
|
386
|
+
// Scheduling the tweet
|
|
387
|
+
const response = await this.request<ITweetScheduleResponse>(resource, { tweet: options });
|
|
388
|
+
|
|
389
|
+
// Deserializing response
|
|
390
|
+
const data = extractors[resource](response);
|
|
391
|
+
|
|
392
|
+
return data;
|
|
393
|
+
}
|
|
394
|
+
|
|
388
395
|
/**
|
|
389
396
|
* Search for tweets using a filter.
|
|
390
397
|
*
|
|
@@ -604,6 +611,42 @@ export class TweetService extends FetcherService {
|
|
|
604
611
|
return data;
|
|
605
612
|
}
|
|
606
613
|
|
|
614
|
+
/**
|
|
615
|
+
* Unschedule a tweet.
|
|
616
|
+
*
|
|
617
|
+
* @param id - The id of the scheduled tweet.
|
|
618
|
+
*
|
|
619
|
+
* @returns Whether unscheduling was successful or not.
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```
|
|
623
|
+
* import { Rettiwt } from 'rettiwt-api';
|
|
624
|
+
*
|
|
625
|
+
* // Creating a new Rettiwt instance using the given 'API_KEY'
|
|
626
|
+
* const rettiwt = new Rettiwt({ apiKey: API_KEY });
|
|
627
|
+
*
|
|
628
|
+
* // Unscheduling the Tweet with id '1234567890'
|
|
629
|
+
* rettiwt.tweet.unschedule('1234567890')
|
|
630
|
+
* .then(res => {
|
|
631
|
+
* console.log(res);
|
|
632
|
+
* })
|
|
633
|
+
* .catch(err => {
|
|
634
|
+
* console.log(err);
|
|
635
|
+
* });
|
|
636
|
+
* ```
|
|
637
|
+
*/
|
|
638
|
+
public async unschedule(id: string): Promise<boolean> {
|
|
639
|
+
const resource = EResourceType.TWEET_UNSCHEDULE;
|
|
640
|
+
|
|
641
|
+
// Unscheduling the tweet
|
|
642
|
+
const response = await this.request<ITweetUnscheduleResponse>(resource, { id: id });
|
|
643
|
+
|
|
644
|
+
// Deserializing the response
|
|
645
|
+
const data = extractors[resource](response) ?? false;
|
|
646
|
+
|
|
647
|
+
return data;
|
|
648
|
+
}
|
|
649
|
+
|
|
607
650
|
/**
|
|
608
651
|
* Upload a media file to Twitter.
|
|
609
652
|
*
|
|
@@ -309,9 +309,8 @@ export class UserService extends FetcherService {
|
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
/**
|
|
312
|
-
* Get the list of tweets liked by
|
|
312
|
+
* Get the list of tweets liked by the logged in user.
|
|
313
313
|
*
|
|
314
|
-
* @param id - The id of the target user.
|
|
315
314
|
* @param count - The number of likes to fetch, must be \<= 100.
|
|
316
315
|
* @param cursor - The cursor to the batch of likes to fetch.
|
|
317
316
|
*
|
|
@@ -324,8 +323,8 @@ export class UserService extends FetcherService {
|
|
|
324
323
|
* // Creating a new Rettiwt instance using the given 'API_KEY'
|
|
325
324
|
* const rettiwt = new Rettiwt({ apiKey: API_KEY });
|
|
326
325
|
*
|
|
327
|
-
* // Fetching the most recent 100 liked Tweets of the
|
|
328
|
-
* rettiwt.user.likes(
|
|
326
|
+
* // Fetching the most recent 100 liked Tweets of the logged in User
|
|
327
|
+
* rettiwt.user.likes()
|
|
329
328
|
* .then(res => {
|
|
330
329
|
* console.log(res);
|
|
331
330
|
* })
|
|
@@ -334,12 +333,12 @@ export class UserService extends FetcherService {
|
|
|
334
333
|
* });
|
|
335
334
|
* ```
|
|
336
335
|
*/
|
|
337
|
-
public async likes(
|
|
336
|
+
public async likes(count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
|
|
338
337
|
const resource = EResourceType.USER_LIKES;
|
|
339
338
|
|
|
340
339
|
// Fetching raw list of likes
|
|
341
340
|
const response = await this.request<IUserLikesResponse>(resource, {
|
|
342
|
-
id:
|
|
341
|
+
id: this.userId,
|
|
343
342
|
count: count,
|
|
344
343
|
cursor: cursor,
|
|
345
344
|
});
|