Skip to content

Commit

Permalink
Merge pull request #537 from Rishikant181/dev
Browse files Browse the repository at this point in the history
v3.0.0
  • Loading branch information
Rishikant181 authored May 14, 2024
2 parents c389c0c + 211b086 commit 6850d58
Show file tree
Hide file tree
Showing 41 changed files with 3,470 additions and 1,168 deletions.
78 changes: 73 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ module.exports = {
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin', 'eslint-plugin-tsdoc'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking'],
plugins: ['@typescript-eslint/eslint-plugin', 'eslint-plugin-tsdoc', 'import'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:import/recommended',
'plugin:import/typescript',
],
root: true,
env: {
node: true,
Expand Down Expand Up @@ -47,14 +52,77 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/explicit-module-boundary-types': 'error',
'@typescript-eslint/explicit-member-accessibility': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-extraneous-class': [
'@typescript-eslint/member-ordering': [
'warn',
{
allowEmpty: true,
default: {
memberTypes: [
// FIELDS

// PRIVATE
'private-static-readonly-field',
'private-static-field',
'private-readonly-field',
'private-field',

// PROTECTED
'protected-static-readonly-field',
'protected-static-field',
'protected-readonly-field',
'protected-field',

// PUBLIC
'public-static-readonly-field',
'public-static-field',
'public-readonly-field',
'public-field',

// CONSTRUCTORS
'private-constructor',
'protected-constructor',
'public-constructor',

// METHODS

// PRIVATE
'private-static-method',
'private-method',

// PROTECTED
'protected-static-method',
'protected-method',

// PUBLIC
'public-static-method',
'public-method',
],
order: 'alphabetically',
},
},
],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-inferrable-types': 'off',
'tsdoc/syntax': 'warn',
'sort-imports': [
'warn',
{
ignoreCase: true,
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
allowSeparatedGroups: false,
},
],
'import/order': [
'warn',
{
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
'newlines-between': 'always-and-inside-groups',
},
],
},
};
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodejs 20.11.1
107 changes: 87 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A CLI tool and an API for fetching data from Twitter for free!

## Prerequisites

- NodeJS 20.10.0
- NodeJS 20
- A working Twitter account (optional)

## Installation
Expand All @@ -19,32 +19,44 @@ It is recommended to install the package globally. Use the following steps to in

Rettiwt-API can be used with or without logging in to Twitter. As such, the two authentication strategies are:

- 'guest' authentication (without logging in) grants access to the following resources:
- 'guest' authentication (without logging in) grants access to the following resources/actions:

- Tweet Details
- User Details
- User Timeline (tweets timeline)
- User Replies (replies timeline)
- User Timeline
- User Replies Timeline

- 'user' authentication (logging in) grants access to the following resources:
- 'user' authentication (logging in) grants access to the following resources/actions:

- Tweet Details
- Tweet Favoriters (likes)
- Tweet Retweeters (retweets)
- Tweet Like
- Tweet Likers
- Tweet List
- Tweet Post
- Tweet Retweet
- Tweet Retweeters
- Tweet Search
- Tweet Stream
- Tweet List
- Tweet Unlike
- Tweet Unpost
- Tweet Unretweet
- Tweet Media Upload
- User Details
- User Follow
- User Followers
- User Following
- User Highlights
- User Likes
- User Timeline (tweets timeline)
- User Replies (replies timeline)
- User Media
- User Replies Timeline
- User Subscriptions
- User Timeline
- User Unfollow

By default, Rettiwt-API uses 'guest' authentication. If however, access to the full set of resources is required, 'user' authentication can be used, which requires the following additional steps post-installtion:

1. Open a terminal.
2. Generate an API_KEY using the command `rettiwt auth login <email> <username> <password>`
2. Generate an API_KEY using the command `rettiwt auth login "<email>" "<username>" "<password>"`

Here,

Expand Down Expand Up @@ -170,11 +182,13 @@ const rettiwt = new Rettiwt({ apiKey: API_KEY });
* - contain the words <word1> and <word2>
*
* 'data' is the response object received in the previous example.
*
* 'count' is a number less or equal to 20 (the quantity of tweets to return)
*/
rettiwt.tweet.search({
fromUsers: ['<username>'],
words: ['<word1>', '<word2>']
}, data.next.value)
}, count, data.next.value)
.then(data => {
...
})
Expand Down Expand Up @@ -251,6 +265,50 @@ Sometimes, when the library shows unexpected behaviour, for troubleshooting purp
const rettiwt = new Rettiwt({ apiKey: API_KEY, logging: true });
```

## Accessing raw response

Rettiwt-API also provides direct access to the raw response data, bypassing any preprocessing by the library itself. This can be achieved by using the [`FetcherService`](https://rishikant181.github.io/Rettiwt-API/classes/FetcherService.html) class instead of the `Rettiwt` class, as demonstrated by the example below, which fetches the raw details of a user with the username 'user1':

- ### JavaScript example:

```js
import { FetcherService, EResourceType } from 'rettiwt-api';

// Creating a new FetcherService instance
const fetcher = new FetcherService({ apiKey: API_KEY });

// Fetching the details of the given user
fetcher
.request(EResourceType.USER_DETAILS_BY_USERNAME, { id: 'user1' })
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
```

- ### TypeScript example:

```ts
import { FetcherService, EResourceType, IUserDetailsResponse } from 'rettiwt-api';

// Creating a new FetcherService instance
const fetcher = new FetcherService({ apiKey: API_KEY });

// Fetching the details of the given user
fetcher
.request<IUserDetailsResponse>(EResourceType.USER_DETAILS_BY_USERNAME, { id: 'user1' })
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
```

As demonstrated by the example, the raw data can be accessed by using the `request` method of the `FetcherService` class, which takes two parameters. The first parameter is the name of the requested resource, while the second is an object specifying the associated arguments required for the given resource. The complete list of resource type can be checked [here](https://rishikant181.github.io/Rettiwt-API/enums/AuthService.html#EResourceType). As for the resource specific argurments, they are the same as that of the methods of `Rettiwt` class' methods for the respective resources, but structured as an object. Notice how the `FetcherService` class takes the same arguments as the `Rettiwt` class, and the arguments have the same effects as they have in case of `Rettiwt` class.

## Features

So far, the following operations are supported:
Expand All @@ -263,23 +321,32 @@ So far, the following operations are supported:
### Tweets

- [Getting the details of a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#details)
- [Favoriting/liking a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#favorite)
- [Getting the list of users who favorited/liked a given tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#favoriters)
- [Liking a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#like)
- [Getting the list of users who liked a given tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#likers)
- [Getting the list of tweets from a given Twitter list](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#list)
- [Retweeting/reposting a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#retweet)
- [Getting the list of users who retweeted/reposted a given tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#retweeters)
- [Posting a new tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#post)
- [Retweeting a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#retweet)
- [Getting the list of users who retweeted a given tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#retweeters)
- [Searching for the list of tweets that match a given filter](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#search)
- [Streaming filtered tweets in pseudo-realtime](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#stream)
- [Posting a new tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#tweet)
- [Unliking a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#unlike)
- [Unposting a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#unpost)
- [Unretweeting a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#unretweet)
- [Uploading a media file for a tweet](https://rishikant181.github.io/Rettiwt-API/classes/TweetService.html#upload)

### Users

- [Getting the details of a user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#details)
- [Following a given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#follow)
- [Getting the list of users who follow the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#followers)
- [Getting the list of users who are followed by the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#following)
- [Getting the list of tweets favorited/liked by the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#likes)
- [Getting the tweet timeline of a user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#timeline)
- [Getting the reply timeline of a user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#replies)
- [Getting the list of highlighted tweets of the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#highlights)
- [Getting the list of tweets liked by the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#likes)
- [Getting the media timeline of the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#media)
- [Getting the replies timeline of the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#replies)
- [Getting the list of subscriptions of the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#subscriptions)
- [Getting the tweet timeline of the given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#timeline)
- [Unfollowing a given user](https://rishikant181.github.io/Rettiwt-API/classes/UserService.html#unfollow)

## CLI Usage

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rettiwt-api",
"version": "2.7.1",
"version": "3.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"description": "An API for fetching data from TwitterAPI, without any rate limits!",
Expand Down Expand Up @@ -30,17 +30,19 @@
"homepage": "https://rishikant181.github.io/Rettiwt-API/",
"dependencies": {
"axios": "1.6.3",
"chalk": "4.1.2",
"class-validator": "0.14.1",
"commander": "11.1.0",
"https-proxy-agent": "7.0.2",
"rettiwt-auth": "2.1.0",
"rettiwt-core": "3.4.0"
"rettiwt-core": "4.0.0"
},
"devDependencies": {
"@types/node": "20.4.1",
"@typescript-eslint/eslint-plugin": "6.0.0",
"@typescript-eslint/parser": "6.0.0",
"eslint": "8.44.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-tsdoc": "0.2.17",
"nodemon": "2.0.20",
"prettier": "3.0.0",
Expand Down
3 changes: 0 additions & 3 deletions src/Rettiwt.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// SERVICES
import { AuthService } from './services/public/AuthService';
import { TweetService } from './services/public/TweetService';
import { UserService } from './services/public/UserService';

// TYPES
import { IRettiwtConfig } from './types/RettiwtConfig';

/**
Expand Down
6 changes: 2 additions & 4 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#! /usr/bin/env node

// PACKAGES
import { createCommand } from 'commander';
import { Rettiwt } from './Rettiwt';

// SUB-COMMANDS
import auth from './commands/Auth';
import tweet from './commands/Tweet';
import user from './commands/User';
import auth from './commands/Auth';
import { Rettiwt } from './Rettiwt';

// Creating a new commandline program
const program = createCommand('rettiwt')
Expand Down
63 changes: 63 additions & 0 deletions src/collections/Extractors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
IInitializeMediaUploadResponse,
IListDetailsResponse,
IResponse,
ITweetLikeResponse,
ITweetPostResponse,
ITweetRetweetResponse,
ITweetUnlikeResponse,
ITweetUnpostResponse,
ITweetUnretweetResponse,
IUserFollowResponse,
IUserUnfollowResponse,
} from 'rettiwt-core';

import { EBaseType } from '../enums/Data';
import { EResourceType } from '../enums/Resource';
import { CursoredData } from '../models/data/CursoredData';
import { Tweet } from '../models/data/Tweet';
import { User } from '../models/data/User';
import { AllReturnTypes } from '../types/ReturnTypes';

/**
* Collection of data extractors for each resource.
*
* @internal
*/
export const extractors: {
[key in keyof typeof EResourceType]: (response: NonNullable<unknown>) => AllReturnTypes | undefined;
} = {
/* eslint-disable @typescript-eslint/naming-convention */
LIST_TWEETS: (response) => new CursoredData<Tweet>(response as IListDetailsResponse, EBaseType.TWEET),

MEDIA_UPLOAD_APPEND: () => undefined,
MEDIA_UPLOAD_FINALIZE: () => undefined,
MEDIA_UPLOAD_INITIALIZE: (response) => (response as IInitializeMediaUploadResponse).media_id_string ?? undefined,

TWEET_DETAILS: (response) => Tweet.single(response as IResponse<unknown>),
TWEET_LIKE: (response) => ((response as ITweetLikeResponse)?.data?.favorite_tweet ? true : false),
TWEET_LIKERS: (response) => new CursoredData<User>(response as IResponse<unknown>, EBaseType.USER),
TWEET_POST: (response) =>
(response as ITweetPostResponse)?.data?.create_tweet?.tweet_results?.result?.rest_id ?? undefined,
TWEET_RETWEET: (response) => ((response as ITweetRetweetResponse)?.data?.create_retweet ? true : false),
TWEET_RETWEETERS: (response) => new CursoredData<User>(response as IResponse<unknown>, EBaseType.USER),
TWEET_SEARCH: (response) => new CursoredData<Tweet>(response as IResponse<unknown>, EBaseType.TWEET),
TWEET_UNLIKE: (response) => ((response as ITweetUnlikeResponse)?.data?.unfavorite_tweet ? true : false),
TWEET_UNPOST: (response) => ((response as ITweetUnpostResponse)?.data?.delete_tweet ? true : false),
TWEET_UNRETWEET: (response) =>
(response as ITweetUnretweetResponse)?.data?.unretweet?.source_tweet_results?.result ? true : false,

USER_DETAILS_BY_USERNAME: (response) => User.single(response as IResponse<unknown>),
USER_DETAILS_BY_ID: (response) => User.single(response as IResponse<unknown>),
USER_FOLLOW: (response) => ((response as IUserFollowResponse)?.id ? true : false),
USER_FOLLOWING: (response) => new CursoredData<User>(response as IResponse<unknown>, EBaseType.USER),
USER_FOLLOWERS: (response) => new CursoredData<User>(response as IResponse<unknown>, EBaseType.USER),
USER_HIGHLIGHTS: (response) => new CursoredData<Tweet>(response as IResponse<unknown>, EBaseType.TWEET),
USER_LIKES: (response) => new CursoredData<Tweet>(response as IResponse<unknown>, EBaseType.TWEET),
USER_MEDIA: (response) => new CursoredData<Tweet>(response as IResponse<unknown>, EBaseType.TWEET),
USER_SUBSCRIPTIONS: (response) => new CursoredData<User>(response as IResponse<unknown>, EBaseType.USER),
USER_TIMELINE: (response) => new CursoredData<Tweet>(response as IResponse<unknown>, EBaseType.TWEET),
USER_TIMELINE_AND_REPLIES: (response) => new CursoredData<Tweet>(response as IResponse<unknown>, EBaseType.TWEET),
USER_UNFOLLOW: (response) => ((response as IUserUnfollowResponse)?.id ? true : false),
/* eslint-enable @typescript-eslint/naming-convention */
};
Loading

0 comments on commit 6850d58

Please sign in to comment.