diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f94630c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+node_modules/
+dist/
+.env
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f40d45e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,93 @@
+![](https://nodei.co/npm/anilist.js.png?downloads=true)\
+NPM module for communicating with Anilist.\
+Find any bugs or have any suggestions?\
+Create an issue on the repo or contact me on Discord @MrScopes#5548
+
+## Table of Contents
+- [Documentation](#documentation)
+- [Notes](#notes)
+
+## Example
+```js
+const Client = require('anilist-js');
+const AniList = new Client('API TOKEN'); // token is only required for some features
+
+(async () => {
+
+ // list the 3 most popular MHA seasons
+ const search = await AniList.searchMedia({ search: 'My Hero Academia', format: 'TV', perPage: 3, sort: 'POPULARITY_DESC' });
+ console.log(search.Results.map(result => result.info.title));
+
+ // toggle favourite status for naruto (character)
+ const characters = await AniList.searchCharacters({ search: 'Naruto Uzumaki' });
+ const naruto = characters.Results[0];
+ await naruto.favourite(); // this requires an api token
+
+})();
+```
+
+## Documentation
+Note: `variables` parameters are 100% auto completion compatible.\
+These docs are most likely temporary.\
+View the [example usage](#example).\
+_Italics_ represents authorization required.
+- Methods:
+ - `.getMedia(id)`
+ - `.searchMedia(variables)`
+
+ - `.getCharacter(id)`
+ - `.searchCharacters(variables)`
+
+ - _`.me()`_ -> Currently authorized user
+ - `.getUser(id)`
+ - `.searchUsers(variables)`
+
+ - `.getStaff(id)`
+ - `.searchStaff(variables)`
+
+ - `.getStudio(id)`
+ - `.searchStudios(variables)`
+
+- Structures:
+ - Search Results:
+ - .Results[\]
+ - .pageInfo
+
+ - `Media >`
+ - .info
+ - _.update(variables)_
+ - _.favourite()_
+
+ - `Character >`
+ - .info
+ - _.favourite()_
+
+ - _`Viewer >`_ represents the current authorized user
+ - _.info_
+ - _.update(variables)_
+ - `User >`
+ - .info
+ - _.follow()_
+
+ - `Staff >`
+ - .info
+ - _.favourite()_
+
+ - `Studio >`
+ - .info
+ - .favourite()
+
+## Notes:
+- This is my first large npm module. So some things might not work 100% as intended.
+
+- The JSON output is massive, so keep the following in mind:
+ - A lot of data is taken out, for example, in user info: statistics is taken out
+ - nodes are taken out. use `edges[] > node`
+ - for `edges[] > node`, only important info is left in like `id`, `title (or name)`
+
+- API Key:
+ - API Keys are needed for user-specific methods, but you can still get media, characters, etc.
+ - Get yours @ [https://anilist-token.glitch.me/](https://anilist-token.glitch.me/). This is secure, created by me, and open source.
+
+- Types:
+ - Types are mainly auto generated, but not every property is 100% supported (this is mainly so the json isn't more massive than it is).
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..5391eaa
--- /dev/null
+++ b/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "anilist.js",
+ "version": "1.0.0",
+ "description": "Communicate with the AniList API.",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "test": "tsc && node dist/test.js"
+ },
+ "keywords": [
+ "anime",
+ "anilist",
+ "typescript"
+ ],
+ "repository": "https://github.com/MrScopes/anilist.js",
+ "author": "MrScopes",
+ "license": "ISC",
+ "dependencies": {
+ "node-fetch": "^2.6.1"
+ },
+ "devDependencies": {
+ "@types/node-fetch": "^2.5.7",
+ "dotenv": "^8.2.0"
+ }
+}
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..f57b34d
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,148 @@
+import Utilities from './utilities';
+import { CharacterQuery } from './queries/queries/character/CharacterQuery';
+import { CharacterSearchQuery } from './queries/queries/character/CharacterSearchQuery';
+import { CharacterSearchResults } from './structures/character/CharacterSearchResults';
+import { CharacterStructure } from './structures/character/CharacterStructure';
+import { MediaQuery } from './queries/queries/media/MediaQuery';
+import { MediaSearchQuery } from './queries/queries/media/MediaSearchQuery';
+import { MediaSearchResults } from './structures/media/MediaSearchResults';
+import { MediaStructure } from './structures/media/MediaStructure';
+import { PageCharactersArgs, PageMediaArgs, PageStaffArgs, PageStudiosArgs, PageUsersArgs } from './types/types';
+import { UserStructure } from './structures/user/UserStructure';
+import { UserSearchResults } from './structures/user/UserSearchResults';
+import { UserSearchQuery } from './queries/queries/user/UserSearchQuery';
+import { UserQuery } from './queries/queries/user/UserQuery';
+import { ViewerQuery } from './queries/queries/user/ViewerQuery';
+import { ViewerStructure } from './structures/user/ViewerStructure';
+import { StaffStructure } from './structures/staff/StaffStructure';
+import { StaffSearchResults } from './structures/staff/StaffSearchResults';
+import { StudioStructure } from './structures/studio/StudioStructure';
+import { StudioSearchResults } from './structures/studio/StudioSearchResults';
+import { StaffQuery } from './queries/queries/staff/StaffQuery';
+import { StaffSearchQuery } from './queries/queries/staff/StaffSearchQuery';
+import { StudioQuery } from './queries/queries/studio/StudioQuery';
+import { StudioSearchQuery } from './queries/queries/studio/StudioSearchQuery';
+
+/** The main anilist.js class. */
+class Client {
+ token?: string;
+ utilities: Utilities;
+
+ /**
+ * "Logs in" to AniList. Required for some features.
+ * @param token API token
+ */
+ constructor(token?: string) {
+ this.utilities = new Utilities();
+ this.token = token;
+ }
+
+ /**
+ * Gets the media with the matching ID.
+ * @param id media id
+ */
+ async getMedia(id: number) {
+ const json = await this.utilities.APIRequest(MediaQuery, { id }, this);
+ return new MediaStructure(json, this);
+ }
+
+ /**
+ * Gets the media with the maching variables.
+ * @param variables filter variables
+ * @example
+ * .searchMedia({ format: 'OVA', includedTags: ['Body Horror'] })
+ */
+ async searchMedia(variables: PageMediaArgs) {
+ const json = await this.utilities.APIRequest(MediaSearchQuery, variables, this);
+ return new MediaSearchResults(json, this);
+ }
+
+ /**
+ * Gets the character with the matching ID.
+ * @param id character id
+ */
+ async getCharacter(id: number) {
+ const json = await this.utilities.APIRequest(CharacterQuery, { id }, this);
+ return new CharacterStructure(json, this);
+ }
+
+ /**
+ * Gets the characters with the maching variables.
+ * @param variables filter variables
+ * @example
+ * .searchCharacters({ name: 'Naruto' })
+ */
+ async searchCharacters(variables: PageCharactersArgs) {
+ const json = await this.utilities.APIRequest(CharacterSearchQuery, variables, this);
+ return new CharacterSearchResults(json, this);
+ }
+
+ /**
+ * Gets the currently authorized user.\
+ * This requires you to be logged in.
+ * @example
+ * .me().info.id
+ */
+ async me() {
+ const json = await this.utilities.APIRequest(ViewerQuery, {}, this);
+ return new ViewerStructure(json, this);
+ }
+
+ /**
+ * Gets the character with the matching ID.
+ * @param id character id
+ */
+ async getUser(id: number) {
+ const json = await this.utilities.APIRequest(UserQuery, { id }, this);
+ return new UserStructure(json, this);
+ }
+
+ /**
+ * Gets the characters with the maching variables.
+ * @param variables filter variables
+ * @example
+ * .searchCharacters({ name: 'Naruto' })
+ */
+ async searchUsers(variables: PageUsersArgs) {
+ const json = await this.utilities.APIRequest(UserSearchQuery, variables, this);
+ return new UserSearchResults(json, this);
+ }
+
+ /**
+ * Gets the staff with the matching ID.
+ * @param id staff id
+ */
+ async getStaff(id: number) {
+ const json = await this.utilities.APIRequest(StaffQuery, { id }, this);
+ return new StaffStructure(json, this);
+ }
+
+ /**
+ * Gets the staff with the matching variables.
+ * @param variables filter variables
+ */
+ async searchStaff(variables: PageStaffArgs) {
+ const json = await this.utilities.APIRequest(StaffSearchQuery, variables, this);
+ return new StaffSearchResults(json, this);
+ }
+
+ /**
+ * Gets the studio with the matching ID.
+ * @param id studio id
+ */
+ async getStudio(id: number) {
+ const json = await this.utilities.APIRequest(StudioQuery, { id }, this);
+ return new StudioStructure(json, this);
+ }
+
+ /**
+ * Gets the studios with the matching variables.
+ * @param variables filter variables
+ */
+ async searchStudios(variables: PageStudiosArgs) {
+ const json = await this.utilities.APIRequest(StudioSearchQuery, variables, this);
+ return new StudioSearchResults(json, this);
+ }
+}
+
+export = Client;
\ No newline at end of file
diff --git a/src/queries/mutations/character/CharacterFavorite.ts b/src/queries/mutations/character/CharacterFavorite.ts
new file mode 100644
index 0000000..f100077
--- /dev/null
+++ b/src/queries/mutations/character/CharacterFavorite.ts
@@ -0,0 +1,15 @@
+const CharacterFavorite = `
+mutation ($id: Int) {
+ ToggleFavourite(characterId: $id) {
+ characters {
+ edges {
+ node {
+ id
+ }
+ }
+ }
+ }
+}
+`
+
+export { CharacterFavorite };
\ No newline at end of file
diff --git a/src/queries/mutations/media/AnimeFavourite.ts b/src/queries/mutations/media/AnimeFavourite.ts
new file mode 100644
index 0000000..11bfd1e
--- /dev/null
+++ b/src/queries/mutations/media/AnimeFavourite.ts
@@ -0,0 +1,15 @@
+const AnimeFavorite = `
+mutation ($id: Int) {
+ ToggleFavourite(animeId: $id) {
+ anime {
+ edges {
+ node {
+ id
+ }
+ }
+ }
+ }
+}
+`
+
+export { AnimeFavorite };
\ No newline at end of file
diff --git a/src/queries/mutations/media/MangaFavourite.ts b/src/queries/mutations/media/MangaFavourite.ts
new file mode 100644
index 0000000..19c8928
--- /dev/null
+++ b/src/queries/mutations/media/MangaFavourite.ts
@@ -0,0 +1,15 @@
+const MangaFavorite = `
+mutation ($id: Int) {
+ ToggleFavourite(mangaId: $id) {
+ manga {
+ edges {
+ node {
+ id
+ }
+ }
+ }
+ }
+}
+`
+
+export { MangaFavorite };
\ No newline at end of file
diff --git a/src/queries/mutations/media/MediaUpdate.ts b/src/queries/mutations/media/MediaUpdate.ts
new file mode 100644
index 0000000..4c8cf07
--- /dev/null
+++ b/src/queries/mutations/media/MediaUpdate.ts
@@ -0,0 +1,32 @@
+const MediaUpdate = `
+mutation ($id: Int, $mediaId: Int, $status: MediaListStatus, $score: Float, $scoreRaw: Int, $progress: Int, $progressVolumes: Int, $repeat: Int, $priority: Int, $private: Boolean, $notes: String, $hiddenFromStatusLists: Boolean, $customLists: [String], $advancedScores: [Float], $startedAt: FuzzyDateInput, $completedAt: FuzzyDateInput) {
+ SaveMediaListEntry(id: $id, mediaId: $mediaId, status: $status, score: $score, scoreRaw: $scoreRaw, progress: $progress, progressVolumes: $progressVolumes, repeat: $repeat, priority: $priority, private: $private, notes: $notes, hiddenFromStatusLists: $hiddenFromStatusLists, customLists: $customLists, advancedScores: $advancedScores, startedAt: $startedAt, completedAt: $completedAt) {
+ id
+ userId
+ mediaId
+ status
+ score
+ progress
+ progressVolumes
+ repeat
+ priority
+ private
+ notes
+ hiddenFromStatusLists
+ customLists
+ advancedScores
+ startedAt {
+ year
+ month
+ day
+ }
+ completedAt {
+ year
+ month
+ day
+ }
+ }
+}
+`
+
+export { MediaUpdate };
\ No newline at end of file
diff --git a/src/queries/mutations/staff/StaffFavourite.ts b/src/queries/mutations/staff/StaffFavourite.ts
new file mode 100644
index 0000000..2d9db1e
--- /dev/null
+++ b/src/queries/mutations/staff/StaffFavourite.ts
@@ -0,0 +1,15 @@
+const StaffFavorite = `
+mutation ($id: Int) {
+ ToggleFavourite(staffId: $id) {
+ staff {
+ edges {
+ node {
+ id
+ }
+ }
+ }
+ }
+}
+`
+
+export { StaffFavorite };
\ No newline at end of file
diff --git a/src/queries/mutations/studio/StudioFavourite.ts b/src/queries/mutations/studio/StudioFavourite.ts
new file mode 100644
index 0000000..afadf33
--- /dev/null
+++ b/src/queries/mutations/studio/StudioFavourite.ts
@@ -0,0 +1,15 @@
+const StudioFavorite = `
+mutation ($id: Int) {
+ ToggleFavourite(studioId: $id) {
+ studios {
+ edges {
+ node {
+ id
+ }
+ }
+ }
+ }
+}
+`
+
+export { StudioFavorite };
\ No newline at end of file
diff --git a/src/queries/mutations/user/UserFollow.ts b/src/queries/mutations/user/UserFollow.ts
new file mode 100644
index 0000000..fd5135a
--- /dev/null
+++ b/src/queries/mutations/user/UserFollow.ts
@@ -0,0 +1,10 @@
+const UserFollow = `
+mutation($userId: Int) {
+ ToggleFollow(userId: $userId) {
+ id
+ name
+ }
+ }
+`
+
+export { UserFollow };
\ No newline at end of file
diff --git a/src/queries/mutations/user/viewer/ViewerUpdate.ts b/src/queries/mutations/user/viewer/ViewerUpdate.ts
new file mode 100644
index 0000000..61c6fe8
--- /dev/null
+++ b/src/queries/mutations/user/viewer/ViewerUpdate.ts
@@ -0,0 +1,11 @@
+const ViewerUpdate = `
+mutation ($about: String, $titleLanguage: UserTitleLanguage, $displayAdultContent: Boolean, $airingNotifications: Boolean, $scoreFormat: ScoreFormat, $rowOrder: String, $profileColor: String, $donatorBadge: String, $notificationOptions: [NotificationOptionInput], $animeListOptions: MediaListOptionsInput, $mangaListOptions: MediaListOptionsInput) {
+ UpdateUser(about: $about, titleLanguage: $titleLanguage, displayAdultContent: $displayAdultContent, airingNotifications: $airingNotifications, scoreFormat: $scoreFormat, rowOrder: $rowOrder, profileColor: $profileColor, donatorBadge: $donatorBadge, notificationOptions: $notificationOptions, animeListOptions: $animeListOptions, mangaListOptions: $mangaListOptions) {
+ id
+ name
+ about
+ }
+ }
+`
+
+export { ViewerUpdate };
\ No newline at end of file
diff --git a/src/queries/queries/character/CharacterQuery.ts b/src/queries/queries/character/CharacterQuery.ts
new file mode 100644
index 0000000..a7a7aea
--- /dev/null
+++ b/src/queries/queries/character/CharacterQuery.ts
@@ -0,0 +1,45 @@
+const CharacterQuery = `
+query ($id: Int) {
+ Character(id: $id) {
+ id
+ name {
+ first
+ last
+ full
+ native
+ alternative
+ }
+ image {
+ large
+ medium
+ }
+ description
+ isFavourite
+ siteUrl
+ media {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ }
+ favourites
+ modNotes
+ }
+}
+`
+
+export { CharacterQuery };
\ No newline at end of file
diff --git a/src/queries/queries/character/CharacterSearchQuery.ts b/src/queries/queries/character/CharacterSearchQuery.ts
new file mode 100644
index 0000000..2405624
--- /dev/null
+++ b/src/queries/queries/character/CharacterSearchQuery.ts
@@ -0,0 +1,54 @@
+const CharacterSearchQuery = `
+query ($search: String, $sort: [CharacterSort], $page: Int, $perPage: Int) {
+ Page(page: $page, perPage: $perPage) {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ Results: characters(search: $search, sort: $sort) {
+ id
+ name {
+ first
+ last
+ full
+ native
+ alternative
+ }
+ image {
+ large
+ medium
+ }
+ description
+ isFavourite
+ siteUrl
+ media {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ }
+ favourites
+ modNotes
+ }
+ }
+}
+`
+
+export { CharacterSearchQuery };
\ No newline at end of file
diff --git a/src/queries/queries/media/MediaQuery.ts b/src/queries/queries/media/MediaQuery.ts
new file mode 100644
index 0000000..c4b6876
--- /dev/null
+++ b/src/queries/queries/media/MediaQuery.ts
@@ -0,0 +1,233 @@
+const MediaQuery = `
+query ($id: Int) {
+ Media(id: $id) {
+ id
+ title {
+ romaji
+ english
+ native
+ }
+ startDate {
+ year
+ month
+ day
+ }
+ endDate {
+ year
+ month
+ day
+ }
+ favourites
+ coverImage {
+ extraLarge
+ large
+ color
+ }
+ characters {
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ role
+ }
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ staff {
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ relations {
+ edges {
+ node {
+ id
+ isAdult
+ title {
+ romaji
+ english
+ native
+ }
+ format
+ type
+ coverImage {
+ large
+ }
+ }
+ relationType
+ }
+ }
+ studios {
+ edges {
+ node {
+ id
+ name
+ }
+ isMain
+ }
+ }
+ recommendations {
+ edges {
+ node {
+ id
+ rating
+ userRating
+ user {
+ id
+ name
+ }
+ }
+ }
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ bannerImage
+ duration
+ format
+ type
+ status
+ episodes
+ chapters
+ volumes
+ season
+ description
+ averageScore
+ meanScore
+ popularity
+ genres
+ siteUrl
+ isFavourite
+ countryOfOrigin
+ isLicensed
+ synonyms
+ trending
+ rankings {
+ id
+ rank
+ type
+ format
+ year
+ season
+ allTime
+ context
+ }
+ stats {
+ scoreDistribution {
+ score
+ amount
+ }
+ statusDistribution {
+ status
+ amount
+ }
+ airingProgression {
+ episode
+ score
+ watching
+ }
+ }
+ tags {
+ id
+ name
+ description
+ isGeneralSpoiler
+ isMediaSpoiler
+ rank
+ }
+ nextAiringEpisode {
+ airingAt
+ timeUntilAiring
+ episode
+ }
+ streamingEpisodes {
+ title
+ thumbnail
+ url
+ site
+ }
+ reviews {
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ mediaListEntry {
+ user {
+ mediaListOptions {
+ scoreFormat
+ animeList {
+ advancedScoring
+ advancedScoringEnabled
+ customLists
+ }
+ mangaList {
+ advancedScoring
+ advancedScoringEnabled
+ customLists
+ }
+ }
+ }
+ id
+ status
+ score
+ progress
+ progressVolumes
+ repeat
+ priority
+ private
+ notes
+ hiddenFromStatusLists
+ customLists(asArray: true)
+ advancedScores
+ startedAt {
+ year
+ month
+ day
+ }
+ completedAt {
+ year
+ month
+ day
+ }
+ updatedAt
+ createdAt
+ }
+ }
+ }
+`
+
+export { MediaQuery };
\ No newline at end of file
diff --git a/src/queries/queries/media/MediaSearchQuery.ts b/src/queries/queries/media/MediaSearchQuery.ts
new file mode 100644
index 0000000..e66b43f
--- /dev/null
+++ b/src/queries/queries/media/MediaSearchQuery.ts
@@ -0,0 +1,242 @@
+const MediaSearchQuery = `
+query ($search: String, $page: Int, $perPage: Int, $sort: [MediaSort], $type: MediaType, $season: MediaSeason, $seasonYear: Int, $format: MediaFormat, $status: MediaStatus, $isAdult: Boolean, $includedGenres: [String], $excludedGenres: [String], $includedTags: [String], $excludedTags: [String], $yearLike: String, $popularityGreaterThan: Int, $averageGreaterThan: Int, $episodesGreaterThan: Int, $episodesLessThan: Int, $country: CountryCode, $source: MediaSource, $licensedBy: [String]) {
+ Page(page: $page, perPage: $perPage) {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ Results: media(search: $search, sort: $sort, type: $type, season: $season, seasonYear: $seasonYear, format: $format, status: $status, isAdult: $isAdult, genre_in: $includedGenres, genre_not_in: $excludedGenres, tag_in: $includedTags, tag_not_in: $excludedTags, startDate_like: $yearLike, popularity_greater: $popularityGreaterThan, averageScore_greater: $averageGreaterThan, episodes_greater: $episodesGreaterThan, episodes_lesser: $episodesLessThan, countryOfOrigin: $country, source: $source, licensedBy_in: $licensedBy) {
+ id
+ title {
+ romaji
+ english
+ native
+ }
+ startDate {
+ year
+ month
+ day
+ }
+ endDate {
+ year
+ month
+ day
+ }
+ favourites
+ coverImage {
+ extraLarge
+ large
+ color
+ }
+ characters {
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ role
+ }
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ staff {
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ relations {
+ edges {
+ node {
+ id
+ isAdult
+ title {
+ romaji
+ english
+ native
+ }
+ format
+ type
+ coverImage {
+ large
+ }
+ }
+ relationType
+ }
+ }
+ studios {
+ edges {
+ node {
+ id
+ name
+ }
+ isMain
+ }
+ }
+ recommendations {
+ edges {
+ node {
+ id
+ rating
+ userRating
+ user {
+ id
+ name
+ }
+ }
+ }
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ bannerImage
+ duration
+ format
+ type
+ status
+ episodes
+ chapters
+ volumes
+ season
+ description
+ averageScore
+ meanScore
+ popularity
+ genres
+ siteUrl
+ isFavourite
+ countryOfOrigin
+ isLicensed
+ synonyms
+ trending
+ rankings {
+ id
+ rank
+ type
+ format
+ year
+ season
+ allTime
+ context
+ }
+ stats {
+ scoreDistribution {
+ score
+ amount
+ }
+ statusDistribution {
+ status
+ amount
+ }
+ airingProgression {
+ episode
+ score
+ watching
+ }
+ }
+ tags {
+ id
+ name
+ description
+ isGeneralSpoiler
+ isMediaSpoiler
+ rank
+ }
+ nextAiringEpisode {
+ airingAt
+ timeUntilAiring
+ episode
+ }
+ streamingEpisodes {
+ title
+ thumbnail
+ url
+ site
+ }
+ reviews {
+ pageInfo {
+ total
+ perPage
+ hasNextPage
+ currentPage
+ lastPage
+ }
+ }
+ mediaListEntry {
+ user {
+ mediaListOptions {
+ scoreFormat
+ animeList {
+ advancedScoring
+ advancedScoringEnabled
+ customLists
+ }
+ mangaList {
+ advancedScoring
+ advancedScoringEnabled
+ customLists
+ }
+ }
+ }
+ id
+ status
+ score
+ progress
+ progressVolumes
+ repeat
+ priority
+ private
+ notes
+ hiddenFromStatusLists
+ customLists(asArray: true)
+ advancedScores
+ startedAt {
+ year
+ month
+ day
+ }
+ completedAt {
+ year
+ month
+ day
+ }
+ updatedAt
+ createdAt
+ }
+ }
+ }
+}
+`
+
+export { MediaSearchQuery };
\ No newline at end of file
diff --git a/src/queries/queries/staff/StaffQuery.ts b/src/queries/queries/staff/StaffQuery.ts
new file mode 100644
index 0000000..0b28748
--- /dev/null
+++ b/src/queries/queries/staff/StaffQuery.ts
@@ -0,0 +1,72 @@
+const StaffQuery = `
+query ($id: Int) {
+ Staff(id: $id) {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ language
+ image {
+ large
+ medium
+ }
+ description
+ isFavourite
+ siteUrl
+ staffMedia {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ }
+ characters {
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ role
+ }
+ }
+ characterMedia {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ }
+ submitter {
+ id
+ name
+ }
+ submissionStatus
+ submissionNotes
+ favourites
+ modNotes
+ }
+ }
+
+`
+
+export { StaffQuery };
\ No newline at end of file
diff --git a/src/queries/queries/staff/StaffSearchQuery.ts b/src/queries/queries/staff/StaffSearchQuery.ts
new file mode 100644
index 0000000..2cb3f14
--- /dev/null
+++ b/src/queries/queries/staff/StaffSearchQuery.ts
@@ -0,0 +1,81 @@
+const StaffSearchQuery = `
+query ($id: Int, $page: Int, $perPage: Int, $search: String, $id_not: Int, $id_in: [Int], $id_not_in: [Int], $sort: [StaffSort]) {
+ Page(page: $page, perPage: $perPage) {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ Results: staff(id: $id, search: $search, id_not: $id_not, id_in: $id_in, id_not_in: $id_not_in, sort: $sort) {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ language
+ image {
+ large
+ medium
+ }
+ description
+ isFavourite
+ siteUrl
+ staffMedia {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ relationType
+ }
+ }
+ characters {
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ role
+ }
+ }
+ characterMedia {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ }
+ submitter {
+ id
+ name
+ }
+ submissionStatus
+ submissionNotes
+ favourites
+ modNotes
+ }
+ }
+ }
+`
+
+export { StaffSearchQuery };
\ No newline at end of file
diff --git a/src/queries/queries/studio/StudioQuery.ts b/src/queries/queries/studio/StudioQuery.ts
new file mode 100644
index 0000000..0a866b4
--- /dev/null
+++ b/src/queries/queries/studio/StudioQuery.ts
@@ -0,0 +1,28 @@
+const StudioQuery = `
+query ($id: Int) {
+ Studio(id: $id) {
+ id
+ name
+ isAnimationStudio
+ media {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ isMainStudio
+ }
+ }
+ siteUrl
+ isFavourite
+ favourites
+ }
+ }
+`
+
+export { StudioQuery };
\ No newline at end of file
diff --git a/src/queries/queries/studio/StudioSearchQuery.ts b/src/queries/queries/studio/StudioSearchQuery.ts
new file mode 100644
index 0000000..8c306a6
--- /dev/null
+++ b/src/queries/queries/studio/StudioSearchQuery.ts
@@ -0,0 +1,38 @@
+const StudioSearchQuery = `
+query ($id: Int, $page: Int, $perPage: Int, $search: String, $id_not: Int, $id_in: [Int], $id_not_in: [Int], $sort: [StudioSort]) {
+ Page(page: $page, perPage: $perPage) {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ Results: studios(id: $id, search: $search, id_not: $id_not, id_in: $id_in, id_not_in: $id_not_in, sort: $sort) {
+ id
+ name
+ isAnimationStudio
+ media {
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ isMainStudio
+ }
+ }
+ siteUrl
+ isFavourite
+ favourites
+ }
+ }
+ }
+
+`
+
+export { StudioSearchQuery };
\ No newline at end of file
diff --git a/src/queries/queries/user/UserQuery.ts b/src/queries/queries/user/UserQuery.ts
new file mode 100644
index 0000000..661780a
--- /dev/null
+++ b/src/queries/queries/user/UserQuery.ts
@@ -0,0 +1,134 @@
+const UserQuery = `
+query ($id: Int) {
+ User(id: $id) {
+ id
+ name
+ about
+ avatar {
+ large
+ medium
+ }
+ bannerImage
+ isFollowing
+ isFollower
+ isBlocked
+ bans
+ options {
+ titleLanguage
+ displayAdultContent
+ airingNotifications
+ profileColor
+ }
+ mediaListOptions {
+ scoreFormat
+ rowOrder
+ useLegacyLists
+ sharedTheme
+ sharedThemeEnabled
+ }
+ favourites {
+ anime {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ }
+ manga {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+
+ }
+ }
+ characters {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ }
+ staff {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ }
+ studios {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ id
+ }
+ }
+ }
+ unreadNotificationCount
+ siteUrl
+ donatorTier
+ donatorBadge
+ moderatorStatus
+ updatedAt
+ }
+ }
+`
+
+export { UserQuery };
\ No newline at end of file
diff --git a/src/queries/queries/user/UserSearchQuery.ts b/src/queries/queries/user/UserSearchQuery.ts
new file mode 100644
index 0000000..827ce76
--- /dev/null
+++ b/src/queries/queries/user/UserSearchQuery.ts
@@ -0,0 +1,142 @@
+const UserSearchQuery = `
+query ($id: Int, $name: String, $search: String, $sort: [UserSort], $page: Int, $perPage: Int) {
+ Page(page: $page, perPage: $perPage) {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ Results: users(id: $id, name: $name, search: $search, sort: $sort) {
+ id
+ name
+ about
+ avatar {
+ large
+ medium
+ }
+ bannerImage
+ isFollowing
+ isFollower
+ isBlocked
+ bans
+ options {
+ titleLanguage
+ displayAdultContent
+ airingNotifications
+ profileColor
+ }
+ mediaListOptions {
+ scoreFormat
+ rowOrder
+ useLegacyLists
+ sharedTheme
+ sharedThemeEnabled
+ }
+ favourites {
+ anime {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ }
+ manga {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ }
+ characters {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ }
+ staff {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ }
+ studios {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ id
+ }
+ }
+ }
+ unreadNotificationCount
+ siteUrl
+ donatorTier
+ donatorBadge
+ moderatorStatus
+ updatedAt
+ }
+ }
+ }
+`
+
+export { UserSearchQuery };
\ No newline at end of file
diff --git a/src/queries/queries/user/ViewerQuery.ts b/src/queries/queries/user/ViewerQuery.ts
new file mode 100644
index 0000000..8605670
--- /dev/null
+++ b/src/queries/queries/user/ViewerQuery.ts
@@ -0,0 +1,134 @@
+const ViewerQuery = `
+query {
+ Viewer {
+ id
+ name
+ about
+ avatar {
+ large
+ medium
+ }
+ bannerImage
+ isFollowing
+ isFollower
+ isBlocked
+ bans
+ options {
+ titleLanguage
+ displayAdultContent
+ airingNotifications
+ profileColor
+ }
+ mediaListOptions {
+ scoreFormat
+ rowOrder
+ useLegacyLists
+ sharedTheme
+ sharedThemeEnabled
+ }
+ favourites {
+ anime {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+ }
+ }
+ manga {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ title {
+ romaji
+ english
+ native
+ userPreferred
+ }
+ }
+
+ }
+ }
+ characters {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ }
+ staff {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ node {
+ id
+ name {
+ first
+ last
+ full
+ native
+ }
+ }
+ }
+ }
+ studios {
+ pageInfo {
+ total
+ perPage
+ currentPage
+ lastPage
+ hasNextPage
+ }
+ edges {
+ id
+ }
+ }
+ }
+ unreadNotificationCount
+ siteUrl
+ donatorTier
+ donatorBadge
+ moderatorStatus
+ updatedAt
+ }
+}
+`
+
+export { ViewerQuery };
\ No newline at end of file
diff --git a/src/structures/character/CharacterSearchResults.ts b/src/structures/character/CharacterSearchResults.ts
new file mode 100644
index 0000000..b6f3a00
--- /dev/null
+++ b/src/structures/character/CharacterSearchResults.ts
@@ -0,0 +1,15 @@
+import Client from '../..';
+import { PageInfo } from '../../types/types';
+import { CharacterStructure } from './CharacterStructure';
+
+/** Search results for an Anime or Manga Character. */
+export class CharacterSearchResults {
+ pageInfo: PageInfo;
+ Results: CharacterStructure[];
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+ this.pageInfo = json.pageInfo;
+ this.Results = json.Results.map((result: any) => new CharacterStructure(result, client));
+ }
+}
\ No newline at end of file
diff --git a/src/structures/character/CharacterStructure.ts b/src/structures/character/CharacterStructure.ts
new file mode 100644
index 0000000..f790e9e
--- /dev/null
+++ b/src/structures/character/CharacterStructure.ts
@@ -0,0 +1,28 @@
+import Client from '../..';
+import { Character } from '../../types/types';
+import { CharacterFavorite } from '../../queries/mutations/character/CharacterFavorite';
+
+/** Represents an Anime or Manga Character. */
+export class CharacterStructure {
+ info: Character;
+ client?: Client;
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+ this.info = json;
+ if (client.token) this.client = client;
+ }
+
+ /**
+ * Toggle this character's favourited status.\
+ * Requires you to be logged in.
+ */
+ async favourite() {
+ if (!this.client?.token) throw new Error('This feature requires you to be logged in.');
+
+ const json = await this.client.utilities.APIRequest(CharacterFavorite, { id: this.info.id }, this.client);
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/structures/media/MediaSearchResults.ts b/src/structures/media/MediaSearchResults.ts
new file mode 100644
index 0000000..8c53413
--- /dev/null
+++ b/src/structures/media/MediaSearchResults.ts
@@ -0,0 +1,16 @@
+import Client from '../..';
+import { PageInfo } from '../../types/types';
+import { MediaStructure } from './MediaStructure';
+
+/** Search results for an Anime or Manga. */
+export class MediaSearchResults {
+ pageInfo: PageInfo;
+ Results: MediaStructure[];
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ this.pageInfo = json.pageInfo;
+ this.Results = json.Results.map((result: any) => new MediaStructure(result, client));
+ }
+}
\ No newline at end of file
diff --git a/src/structures/media/MediaStructure.ts b/src/structures/media/MediaStructure.ts
new file mode 100644
index 0000000..724948e
--- /dev/null
+++ b/src/structures/media/MediaStructure.ts
@@ -0,0 +1,50 @@
+import Client from '../..';
+import { Media, MutationSaveMediaListEntryArgs } from '../../types/types';
+import { MediaUpdate } from '../../queries/mutations/media/MediaUpdate';
+import { AnimeFavorite } from '../../queries/mutations/media/AnimeFavourite';
+import { MangaFavorite } from '../../queries/mutations/media/MangaFavourite';
+
+/** Represents an Anime or Manga. */
+export class MediaStructure {
+ info: Media;
+ client?: Client;
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+ this.info = json;
+ if (client.token) this.client = client;
+ }
+
+ /**
+ * Update an entry.\
+ * **REQUIRES YOU TO BE LOGGED IN!**
+ * @param entry what to update
+ * @example
+ * .update({ score: 80, completedAt: Date.now() });
+ */
+ async update(entry: MutationSaveMediaListEntryArgs) {
+ if (!this.client?.token) throw new Error('This feature requires you to be logged in.');
+
+ Object.assign(entry, { mediaId: this.info.id });
+ const json = await this.client.utilities.APIRequest(MediaUpdate, entry, this.client);
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ return json;
+ }
+
+ /**
+ * Toggle this media's favourited status.\
+ * Requires you to be logged in.
+ */
+ async favourite() {
+ if (!this.client?.token) throw new Error('This feature requires you to be logged in.');
+
+ let mutation = AnimeFavorite;
+ if (this.info.format === 'MANGA') mutation = MangaFavorite;
+
+ const json = await this.client.utilities.APIRequest(mutation, { id: this.info.id }, this.client);
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/structures/staff/StaffSearchResults.ts b/src/structures/staff/StaffSearchResults.ts
new file mode 100644
index 0000000..89b9186
--- /dev/null
+++ b/src/structures/staff/StaffSearchResults.ts
@@ -0,0 +1,16 @@
+import Client from '../..';
+import { PageInfo } from '../../types/types';
+import { StaffStructure } from './StaffStructure';
+
+/** Search results for a Voice actor or production staff. */
+export class StaffSearchResults {
+ pageInfo: PageInfo;
+ Results: StaffStructure[];
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ this.pageInfo = json.pageInfo;
+ this.Results = json.Results.map((result: any) => new StaffStructure(result, client));
+ }
+}
\ No newline at end of file
diff --git a/src/structures/staff/StaffStructure.ts b/src/structures/staff/StaffStructure.ts
new file mode 100644
index 0000000..ded0d7d
--- /dev/null
+++ b/src/structures/staff/StaffStructure.ts
@@ -0,0 +1,28 @@
+import Client from '../..';
+import { StaffFavorite } from '../../queries/mutations/staff/StaffFavourite';
+import { Staff } from '../../types/types';
+
+/** Represents a Voice actor or production staff. */
+export class StaffStructure {
+ info: Staff;
+ client?: Client;
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+ this.info = json;
+ if (client.token) this.client = client;
+ }
+
+ /**
+ * Toggle this staff's favourited status.\
+ * Requires you to be logged in.
+ */
+ async favourite() {
+ if (!this.client?.token) throw new Error('This feature requires you to be logged in.');
+
+ const json = await this.client.utilities.APIRequest(StaffFavorite, { id: this.info.id }, this.client);
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/structures/studio/StudioSearchResults.ts b/src/structures/studio/StudioSearchResults.ts
new file mode 100644
index 0000000..08cea17
--- /dev/null
+++ b/src/structures/studio/StudioSearchResults.ts
@@ -0,0 +1,16 @@
+import Client from '../..';
+import { PageInfo } from '../../types/types';
+import { StudioStructure } from './StudioStructure';
+
+/** Search results for an Animation or production company. */
+export class StudioSearchResults {
+ pageInfo: PageInfo;
+ Results: StudioStructure[];
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ this.pageInfo = json.pageInfo;
+ this.Results = json.Results.map((result: any) => new StudioStructure(result, client));
+ }
+}
\ No newline at end of file
diff --git a/src/structures/studio/StudioStructure.ts b/src/structures/studio/StudioStructure.ts
new file mode 100644
index 0000000..33f8103
--- /dev/null
+++ b/src/structures/studio/StudioStructure.ts
@@ -0,0 +1,28 @@
+import Client from '../..';
+import { StudioFavorite } from '../../queries/mutations/studio/StudioFavourite';
+import { Studio } from '../../types/types';
+
+/** Represents an Animation or production company. */
+export class StudioStructure {
+ info: Studio;
+ client?: Client;
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+ this.info = json;
+ if (client.token) this.client = client;
+ }
+
+ /**
+ * Toggle this studio's favourited status.\
+ * Requires you to be logged in.
+ */
+ async favourite() {
+ if (!this.client?.token) throw new Error('This feature requires you to be logged in.');
+
+ const json = await this.client.utilities.APIRequest(StudioFavorite, { id: this.info.id }, this.client);
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/structures/user/UserSearchResults.ts b/src/structures/user/UserSearchResults.ts
new file mode 100644
index 0000000..0f6c694
--- /dev/null
+++ b/src/structures/user/UserSearchResults.ts
@@ -0,0 +1,16 @@
+import Client from '../..';
+import { PageInfo } from '../../types/types';
+import { UserStructure } from './UserStructure';
+
+/** Represents search results for an AniList User. */
+export class UserSearchResults {
+ pageInfo: PageInfo;
+ Results: UserStructure[];
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ this.pageInfo = json.pageInfo;
+ this.Results = json.Results.map((result: any) => new UserStructure(result, client));
+ }
+}
\ No newline at end of file
diff --git a/src/structures/user/UserStructure.ts b/src/structures/user/UserStructure.ts
new file mode 100644
index 0000000..771f0a4
--- /dev/null
+++ b/src/structures/user/UserStructure.ts
@@ -0,0 +1,28 @@
+import Client from '../..';
+import { UserFollow } from '../../queries/mutations/user/UserFollow';
+import { User } from '../../types/types';
+
+/** Represents an AniList User. */
+export class UserStructure {
+ info: User;
+ client?: Client;
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+ this.info = json;
+ if (client.token) this.client = client;
+ }
+
+ /**
+ * Follow this user.\
+ * Requires you to be logged in.
+ */
+ async follow() {
+ if (!this.client?.token) throw new Error('This feature requires you to be logged in.');
+
+ const json = await this.client.utilities.APIRequest(UserFollow, { userId: this.info.id }, this.client);
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/structures/user/ViewerStructure.ts b/src/structures/user/ViewerStructure.ts
new file mode 100644
index 0000000..a9a09a8
--- /dev/null
+++ b/src/structures/user/ViewerStructure.ts
@@ -0,0 +1,31 @@
+import Client from '../..';
+import { ViewerUpdate } from '../../queries/mutations/user/viewer/ViewerUpdate';
+import { MutationUpdateUserArgs, User } from '../../types/types';
+
+/** Represents the client user. */
+export class ViewerStructure {
+ info: User;
+ client?: Client;
+
+ constructor(json: any, client: Client) {
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+ this.info = json;
+ if (client.token) this.client = client;
+ }
+
+ /**
+ * Update the authorized user.\
+ * Requires you to be logged in.
+ * @param entry what to update
+ * @example
+ * .update({ about: 'Hi' });
+ */
+ async update(entry: MutationUpdateUserArgs) {
+ if (!this.client?.token) throw new Error('This feature requires you to be logged in.');
+
+ const json = await this.client.utilities.APIRequest(ViewerUpdate, entry, this.client);
+ if (json.errors) throw new Error(JSON.stringify(json.errors));
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/test.ts b/src/test.ts
new file mode 100644
index 0000000..3e32ec8
--- /dev/null
+++ b/src/test.ts
@@ -0,0 +1,9 @@
+require('dotenv').config();
+
+import Client from './index';
+const AniList = new Client(process.env.token);
+
+(async function () {
+ const me = await AniList.getMedia(1);
+ me.update({ score: 10 });
+})();
\ No newline at end of file
diff --git a/src/types/custom/Genres.ts b/src/types/custom/Genres.ts
new file mode 100644
index 0000000..cdeb2af
--- /dev/null
+++ b/src/types/custom/Genres.ts
@@ -0,0 +1,21 @@
+export type Genres =
+| 'ACTION'
+| 'ADVENTURE'
+| 'COMEDY'
+| 'DRAMA'
+| 'ECCHI'
+| 'FANTASY'
+| 'HORROR'
+| 'HENTAI'
+| 'MAHOU SHOUJO'
+| 'MECHA'
+| 'MECHA'
+| 'MUSIC'
+| 'MYSTERY'
+| 'PSYCHOLOGICAL'
+| 'ROMANCE'
+| 'SCI-FI'
+| 'SLICE OF LIFE'
+| 'SPORTS'
+| 'SUPERNATURAL'
+| 'THRILLER';
\ No newline at end of file
diff --git a/src/types/custom/Tags.ts b/src/types/custom/Tags.ts
new file mode 100644
index 0000000..f37865b
--- /dev/null
+++ b/src/types/custom/Tags.ts
@@ -0,0 +1,289 @@
+export type Tags =
+| '4-koma'
+| 'Achromatic'
+| 'Achronological Order'
+| 'Acting'
+| 'Advertisement'
+| 'Afterlife'
+| 'Age Gap'
+| 'Age Regression'
+| 'Agender'
+| 'Ahegao'
+| 'Airsoft'
+| 'Aliens'
+| 'Alternate Universe'
+| 'American Football'
+| 'Amnesia'
+| 'Amputation'
+| 'Anachronism'
+| 'Anal Sex'
+| 'Animals'
+| 'Anthology'
+| 'Anti-Hero'
+| 'Archery'
+| 'Armpits'
+| 'Artificial Intelligence'
+| 'Asexual'
+| 'Ashikoki'
+| 'Asphyxiation'
+| 'Assassins'
+| 'Astronomy'
+| 'Athletics'
+| 'Augmented Reality'
+| 'Autobiographical'
+| 'Aviation'
+| 'Badminton'
+| 'Band'
+| 'Bar'
+| 'Baseball'
+| 'Basketball'
+| 'Battle Royale'
+| 'Biographical'
+| 'Bisexual'
+| 'Blackmail'
+| 'Body Horror'
+| 'Body Swapping'
+| 'Bondage'
+| 'Boobjob'
+| 'Boxing'
+| 'Boys Love'
+| 'Bullying'
+| 'Calligraphy'
+| 'Card Battle'
+| 'Cars'
+| 'Centaur'
+| 'CGI'
+| 'Cheerleading'
+| 'Chibi'
+| 'Chimera'
+| 'Chuunibyou'
+| 'Circus'
+| 'Classic Literature'
+| 'College'
+| 'Coming of Age'
+| 'Conspiracy'
+| 'Cosmic Horror'
+| 'Cosplay'
+| 'Crime'
+| 'Crossdressing'
+| 'Crossover'
+| 'Cult'
+| 'Cultivation'
+| 'Cunnilingus'
+| 'Cute Girls Doing Cute Things'
+| 'Cyberpunk'
+| 'Cycling'
+| 'Dancing'
+| 'Dark Skin'
+| 'Death Game'
+| 'Defloration'
+| 'Delinquents'
+| 'Demons'
+| 'Denpa'
+| 'Detective'
+| 'Dinosaurs'
+| 'Dissociative Identities'
+| 'Dragons'
+| 'Drawing'
+| 'Drugs'
+| 'Dullahan'
+| 'Dungeon'
+| 'Dystopian'
+| 'Economics'
+| 'Educational'
+| 'Elf'
+| 'Ensemble Cast'
+| 'Environmental'
+| 'Episodic'
+| 'Ero Guro'
+| 'Espionage'
+| 'Facial'
+| 'Fairy Tale'
+| 'Family Life'
+| 'Fashion'
+| 'Feet'
+| 'Fellatio'
+| 'Female Protagonist'
+| 'Firefighters'
+| 'Fishing'
+| 'Fitness'
+| 'Flash'
+| 'Flat Chest'
+| 'Food'
+| 'Football'
+| 'Foreign'
+| 'Fugitive'
+| 'Full CGI'
+| 'Full Color'
+| 'Futanari'
+| 'Gambling'
+| 'Gangs'
+| 'Gender Bending'
+| 'Ghost'
+| 'Go'
+| 'Goblin'
+| 'Gods'
+| 'Golf'
+| 'Gore'
+| 'Guns'
+| 'Gyaru'
+| 'Handjob'
+| 'Harem'
+| 'Henshin'
+| 'Hikikomori'
+| 'Historical'
+| 'Human Pet'
+| 'Ice Skating'
+| 'Idol'
+| 'Incest'
+| 'Irrumatio'
+| 'Isekai'
+| 'Iyashikei'
+| 'Josei'
+| 'Kaiju'
+| 'Karuta'
+| 'Kemonomimi'
+| 'Kids'
+| 'Kuudere'
+| 'Lacrosse'
+| 'Lactation'
+| 'Language Barrier'
+| 'Large Breasts'
+| 'LGBTQ Issues'
+| 'Lost Civilization'
+| 'Love Triangle'
+| 'Mafia'
+| 'Magic'
+| 'Mahjong'
+| 'Maids'
+| 'Male Protagonist'
+| 'Martial Arts'
+| 'Masturbation'
+| 'Medicine'
+| 'Memory Manipulation'
+| 'Mermaid'
+| 'Meta'
+| 'MILF'
+| 'Military'
+| 'Monster Girl'
+| 'Mopeds'
+| 'Motorcycles'
+| 'Musical'
+| 'Mythology'
+| 'Nakadashi'
+| 'Nekomimi'
+| 'Netorare'
+| 'Netorase'
+| 'Netori'
+| 'Ninja'
+| 'No Dialogue'
+| 'Noir'
+| 'Nudity'
+| 'Nun'
+| 'Office Lady'
+| 'Oiran'
+| 'Ojou-sama'
+| 'Omegaverse'
+| 'Otaku Culture'
+| 'Outdoor'
+| 'Parody'
+| 'Philosophy'
+| 'Photography'
+| 'Pirates'
+| 'Poker'
+| 'Police'
+| 'Politics'
+| 'Post-Apocalyptic'
+| 'POV'
+| 'Pregnant'
+| 'Primarily Adult Cast'
+| 'Primarily Child Cast'
+| 'Primarily Female Cast'
+| 'Primarily Male Cast'
+| 'Prostitution'
+| 'Public Sex'
+| 'Puppetry'
+| 'Rakugo'
+| 'Rape'
+| 'Real Robot'
+| 'Rehabilitation'
+| 'Reincarnation'
+| 'Revenge'
+| 'Reverse Harem'
+| 'Rimjob'
+| 'Robots'
+| 'Rotoscoping'
+| 'Rugby'
+| 'Rural'
+| 'Sadism'
+| 'Samurai'
+| 'Satire'
+| 'Scat'
+| 'School'
+| 'School Club'
+| 'Seinen'
+| 'Sex Toys'
+| 'Shapeshifting'
+| 'Ships'
+| 'Shogi'
+| 'Shoujo'
+| 'Shounen'
+| 'Shrine Maiden'
+| 'Skeleton'
+| 'Slapstick'
+| 'Slavery'
+| 'Software Development'
+| 'Space'
+| 'Space Opera'
+| 'Steampunk'
+| 'Stop Motion'
+| 'Succubus'
+| 'Sumata'
+| 'Super Power'
+| 'Super Robot'
+| 'Superhero'
+| 'Surfing'
+| 'Surreal Comedy'
+| 'Survival'
+| 'Sweat'
+| 'Swimming'
+| 'Swordplay'
+| 'Table Tennis'
+| 'Tanks'
+| 'Teacher'
+| 'Teens Love'
+| 'Tennis'
+| 'Tentacles'
+| 'Terrorism'
+| 'Threesome'
+| 'Time Manipulation'
+| 'Time Skip'
+| 'Tokusatsu'
+| 'Tragedy'
+| 'Trains'
+| 'Triads'
+| 'Tsundere'
+| 'Twins'
+| 'Urban'
+| 'Urban Fantasy'
+| 'Urination'
+| 'Vampire'
+| 'Video Games'
+| 'Vikings'
+| 'Virginity'
+| 'Virtual World'
+| 'Volleyball'
+| 'Vore'
+| 'Voyeur'
+| 'War'
+| 'Werewolf'
+| 'Witch'
+| 'Work'
+| 'Wrestling'
+| 'Writing'
+| 'Wuxia'
+| 'Yakuza'
+| 'Yandere'
+| 'Youkai'
+| 'Yuri'
+| 'Zombie';
\ No newline at end of file
diff --git a/src/types/types.ts b/src/types/types.ts
new file mode 100644
index 0000000..4830d0c
--- /dev/null
+++ b/src/types/types.ts
@@ -0,0 +1,4147 @@
+import { Genres } from './custom/Genres';
+import { Tags } from './custom/Tags';
+
+export type Maybe = T | null;
+export type Exact = { [K in keyof T]: T[K] };
+export type MakeOptional = Omit & { [SubKey in K]?: Maybe };
+export type MakeMaybe = Omit & { [SubKey in K]: Maybe };
+/** All built-in and custom scalars, mapped to their actual values */
+export type Scalars = {
+ ID: string;
+ String: string;
+ Boolean: boolean;
+ Int: number;
+ Float: number;
+ Json: any;
+ /** ISO 3166-1 alpha-2 country code */
+ CountryCode: any;
+ /** 8 digit long date integer (YYYYMMDD). Unknown dates represented by 0. E.g. 2016: 20160000, May 1976: 19760500 */
+ FuzzyDateInt: any;
+ Genre: Genres;
+ Tag: Tags;
+};
+
+export type Query = {
+ Page?: Maybe;
+ /** Media query */
+ Media?: Maybe;
+ /** Media Trend query */
+ MediaTrend?: Maybe;
+ /** Airing schedule query */
+ AiringSchedule?: Maybe;
+ /** Character query */
+ Character?: Maybe;
+ /** Staff query */
+ Staff?: Maybe;
+ /** Media list query */
+ MediaList?: Maybe;
+ /** Media list collection query, provides list pre-grouped by status & custom lists. User ID and Media Type arguments required. */
+ MediaListCollection?: Maybe;
+ /** Collection of all the possible media genres */
+ GenreCollection?: Maybe>>;
+ /** Collection of all the possible media tags */
+ MediaTagCollection?: Maybe>>;
+ /** User query */
+ User?: Maybe;
+ /** Get the currently authenticated user */
+ Viewer?: Maybe;
+ /** Notification query */
+ Notification?: Maybe;
+ /** Studio query */
+ Studio?: Maybe;
+ /** Review query */
+ Review?: Maybe;
+ /** Activity query */
+ Activity?: Maybe;
+ /** Activity reply query */
+ ActivityReply?: Maybe;
+ /** Follow query */
+ Following?: Maybe;
+ /** Follow query */
+ Follower?: Maybe;
+ /** Thread query */
+ Thread?: Maybe;
+ /** Comment query */
+ ThreadComment?: Maybe>>;
+ /** Recommendation query */
+ Recommendation?: Maybe;
+ /** Like query */
+ Like?: Maybe;
+ /** Provide AniList markdown to be converted to html (Requires auth) */
+ Markdown?: Maybe;
+ AniChartUser?: Maybe;
+ /** Site statistics query */
+ SiteStatistics?: Maybe;
+};
+
+
+export type QueryPageArgs = {
+ page?: Maybe;
+ perPage?: Maybe;
+};
+
+
+export type QueryMediaArgs = {
+ id?: Maybe;
+ idMal?: Maybe;
+ startDate?: Maybe;
+ endDate?: Maybe;
+ season?: Maybe;
+ seasonYear?: Maybe;
+ type?: Maybe;
+ format?: Maybe;
+ status?: Maybe;
+ episodes?: Maybe;
+ duration?: Maybe;
+ chapters?: Maybe;
+ volumes?: Maybe;
+ isAdult?: Maybe;
+ genre?: Maybe;
+ tag?: Maybe;
+ minimumTagRank?: Maybe;
+ tagCategory?: Maybe;
+ onList?: Maybe;
+ licensedBy?: Maybe;
+ averageScore?: Maybe;
+ popularity?: Maybe;
+ source?: Maybe;
+ countryOfOrigin?: Maybe;
+ search?: Maybe;
+ id_not?: Maybe;
+ id_in?: Maybe>>;
+ id_not_in?: Maybe>>;
+ idMal_not?: Maybe;
+ idMal_in?: Maybe>>;
+ idMal_not_in?: Maybe>>;
+ startDate_greater?: Maybe;
+ startDate_lesser?: Maybe;
+ startDate_like?: Maybe;
+ endDate_greater?: Maybe;
+ endDate_lesser?: Maybe;
+ endDate_like?: Maybe;
+ format_in?: Maybe>>;
+ format_not?: Maybe;
+ format_not_in?: Maybe>>;
+ status_in?: Maybe>>;
+ status_not?: Maybe;
+ status_not_in?: Maybe>>;
+ episodes_greater?: Maybe;
+ episodes_lesser?: Maybe;
+ duration_greater?: Maybe;
+ duration_lesser?: Maybe;
+ chapters_greater?: Maybe;
+ chapters_lesser?: Maybe;
+ volumes_greater?: Maybe;
+ volumes_lesser?: Maybe;
+ genre_in?: Maybe>>;
+ genre_not_in?: Maybe>>;
+ tag_in?: Maybe>>;
+ tag_not_in?: Maybe>>;
+ tagCategory_in?: Maybe>>;
+ tagCategory_not_in?: Maybe>>;
+ licensedBy_in?: Maybe>>;
+ averageScore_not?: Maybe;
+ averageScore_greater?: Maybe;
+ averageScore_lesser?: Maybe;
+ popularity_not?: Maybe;
+ popularity_greater?: Maybe;
+ popularity_lesser?: Maybe;
+ source_in?: Maybe>>;
+ sort?: Maybe>>;
+};
+
+
+export type QueryMediaTrendArgs = {
+ mediaId?: Maybe;
+ date?: Maybe;
+ trending?: Maybe;
+ averageScore?: Maybe;
+ popularity?: Maybe;
+ episode?: Maybe;
+ releasing?: Maybe;
+ mediaId_not?: Maybe;
+ mediaId_in?: Maybe>>;
+ mediaId_not_in?: Maybe>>;
+ date_greater?: Maybe;
+ date_lesser?: Maybe;
+ trending_greater?: Maybe;
+ trending_lesser?: Maybe;
+ trending_not?: Maybe;
+ averageScore_greater?: Maybe;
+ averageScore_lesser?: Maybe;
+ averageScore_not?: Maybe;
+ popularity_greater?: Maybe;
+ popularity_lesser?: Maybe;
+ popularity_not?: Maybe;
+ episode_greater?: Maybe;
+ episode_lesser?: Maybe;
+ episode_not?: Maybe;
+ sort?: Maybe>>;
+};
+
+
+export type QueryAiringScheduleArgs = {
+ id?: Maybe;
+ mediaId?: Maybe;
+ episode?: Maybe;
+ airingAt?: Maybe;
+ notYetAired?: Maybe;
+ id_not?: Maybe;
+ id_in?: Maybe>>;
+ id_not_in?: Maybe>>;
+ mediaId_not?: Maybe;
+ mediaId_in?: Maybe>>;
+ mediaId_not_in?: Maybe>>;
+ episode_not?: Maybe;
+ episode_in?: Maybe>>;
+ episode_not_in?: Maybe>>;
+ episode_greater?: Maybe;
+ episode_lesser?: Maybe;
+ airingAt_greater?: Maybe;
+ airingAt_lesser?: Maybe;
+ sort?: Maybe>>;
+};
+
+
+export type QueryCharacterArgs = {
+ id?: Maybe;
+ search?: Maybe;
+ id_not?: Maybe;
+ id_in?: Maybe>>;
+ id_not_in?: Maybe>>;
+ sort?: Maybe>>;
+};
+
+
+export type QueryStaffArgs = {
+ id?: Maybe;
+ search?: Maybe;
+ id_not?: Maybe;
+ id_in?: Maybe>>;
+ id_not_in?: Maybe>>;
+ sort?: Maybe>>;
+};
+
+
+export type QueryMediaListArgs = {
+ id?: Maybe;
+ userId?: Maybe;
+ userName?: Maybe;
+ type?: Maybe;
+ status?: Maybe;
+ mediaId?: Maybe;
+ isFollowing?: Maybe;
+ notes?: Maybe;
+ startedAt?: Maybe;
+ completedAt?: Maybe;
+ compareWithAuthList?: Maybe;
+ userId_in?: Maybe>>;
+ status_in?: Maybe>>;
+ status_not_in?: Maybe>>;
+ status_not?: Maybe;
+ mediaId_in?: Maybe>>;
+ mediaId_not_in?: Maybe>>;
+ notes_like?: Maybe;
+ startedAt_greater?: Maybe;
+ startedAt_lesser?: Maybe;
+ startedAt_like?: Maybe;
+ completedAt_greater?: Maybe;
+ completedAt_lesser?: Maybe;
+ completedAt_like?: Maybe;
+ sort?: Maybe>>;
+};
+
+
+export type QueryMediaListCollectionArgs = {
+ userId?: Maybe;
+ userName?: Maybe;
+ type?: Maybe;
+ status?: Maybe;
+ notes?: Maybe;
+ startedAt?: Maybe;
+ completedAt?: Maybe;
+ forceSingleCompletedList?: Maybe;
+ chunk?: Maybe;
+ perChunk?: Maybe;
+ status_in?: Maybe>>;
+ status_not_in?: Maybe>>;
+ status_not?: Maybe;
+ notes_like?: Maybe;
+ startedAt_greater?: Maybe;
+ startedAt_lesser?: Maybe;
+ startedAt_like?: Maybe;
+ completedAt_greater?: Maybe;
+ completedAt_lesser?: Maybe;
+ completedAt_like?: Maybe;
+ sort?: Maybe>>;
+};
+
+
+export type QueryMediaTagCollectionArgs = {
+ status?: Maybe;
+};
+
+
+export type QueryUserArgs = {
+ id?: Maybe;
+ name?: Maybe;
+ search?: Maybe;
+ sort?: Maybe>>;
+};
+
+
+export type QueryNotificationArgs = {
+ type?: Maybe;
+ resetNotificationCount?: Maybe;
+ type_in?: Maybe>>;
+};
+
+
+export type QueryStudioArgs = {
+ id?: Maybe;
+ search?: Maybe;
+ id_not?: Maybe;
+ id_in?: Maybe>>;
+ id_not_in?: Maybe>>;
+ sort?: Maybe>>;
+};
+
+
+export type QueryReviewArgs = {
+ id?: Maybe;
+ mediaId?: Maybe;
+ userId?: Maybe;
+ mediaType?: Maybe;
+ sort?: Maybe>>;
+};
+
+
+export type QueryActivityArgs = {
+ id?: Maybe;
+ userId?: Maybe;
+ messengerId?: Maybe;
+ mediaId?: Maybe;
+ type?: Maybe;
+ isFollowing?: Maybe;
+ hasReplies?: Maybe;
+ hasRepliesOrTypeText?: Maybe;
+ createdAt?: Maybe;
+ id_not?: Maybe;
+ id_in?: Maybe>>;
+ id_not_in?: Maybe>>;
+ userId_not?: Maybe;
+ userId_in?: Maybe>>;
+ userId_not_in?: Maybe>>;
+ messengerId_not?: Maybe;
+ messengerId_in?: Maybe>>;
+ messengerId_not_in?: Maybe>>;
+ mediaId_not?: Maybe;
+ mediaId_in?: Maybe>>;
+ mediaId_not_in?: Maybe>>;
+ type_not?: Maybe;
+ type_in?: Maybe>>;
+ type_not_in?: Maybe>>;
+ createdAt_greater?: Maybe;
+ createdAt_lesser?: Maybe;
+ sort?: Maybe>>;
+};
+
+
+export type QueryActivityReplyArgs = {
+ id?: Maybe;
+ activityId?: Maybe;
+};
+
+
+export type QueryFollowingArgs = {
+ userId: Scalars['Int'];
+ sort?: Maybe>>;
+};
+
+
+export type QueryFollowerArgs = {
+ userId: Scalars['Int'];
+ sort?: Maybe