@sodiumlabs/gdapi
Version:
An unofficial Geometry Dash API wrapper
1 lines • 65 kB
Source Map (JSON)
{"version":3,"sources":["../src/resources/gauntlets.ts","../src/resources/levels.ts","../src/resources/lists.ts","../src/resources/mapPacks.ts","../src/resources/songs.ts","../src/resources/users.ts","../src/APIError.ts","../src/constants.ts","../src/GDAPI.ts","../src/parser.ts","../src/REST.ts","../src/secrets.ts","../src/requests.ts","../src/index.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const gauntletMappings = {\n 1: \"id\",\n 3: \"levels\",\n};\n\nexport enum GauntletName {\n Fire = 1,\n Ice = 2,\n Poison = 3,\n Shadow = 4,\n Lava = 5,\n Bonus = 6,\n Chaos = 7,\n Demon = 8,\n Time = 9,\n Crystal = 10,\n Magic = 11,\n Spike = 12,\n Monster = 13,\n Doom = 14,\n Death = 15,\n Forest = 16,\n Force = 18,\n Water = 21,\n Haunted = 22,\n Halloween = 29,\n Inferno = 33,\n Portal = 34,\n Strange = 35,\n Fantasy = 36,\n Christmas = 37,\n Mystery = 39,\n Cursed = 40,\n Cyborg = 41,\n Castle = 42,\n World = 46,\n Galaxy = 47,\n Universe = 48,\n Discord = 49,\n Split = 50,\n NCSI = 51,\n NCSII = 52,\n}\n\nexport const gauntletSchema = z.object({\n /**\n * The gauntlet ID\n */\n id: z.coerce.number().int(),\n /**\n * The level IDs\n */\n levels: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int())),\n});\n\nexport type Gauntlet = z.infer<typeof gauntletSchema>;\n","import { z } from \"zod\";\n\nexport const levelMappings = {\n 1: \"id\",\n 2: \"name\",\n 3: \"description\",\n 5: \"version\",\n 6: \"playerId\",\n 8: \"difficultyDenominator\",\n 9: \"difficultyNumerator\",\n 10: \"downloads\",\n 12: \"officialSong\",\n 13: \"gameVersion\",\n 14: \"likes\",\n 15: \"length\",\n 16: \"dislikes\",\n 17: \"demon\",\n 18: \"stars\",\n 19: \"featureScore\",\n 25: \"auto\",\n 30: \"copiedId\",\n 31: \"twoPlayer\",\n 35: \"customSongId\",\n 37: \"coins\",\n 38: \"verifiedCoins\",\n 39: \"starsRequested\",\n 42: \"epic\",\n 43: \"demonDifficulty\",\n 44: \"isGauntlet\",\n 45: \"objects\",\n};\n\nexport enum LevelDifficultyDenominator {\n NA = 0,\n Assigned = 10,\n}\n\nexport enum LevelDifficultyNumerator {\n Unrated = 0,\n Easy = 10,\n Normal = 20,\n Hard = 30,\n Harder = 40,\n Insane = 50,\n}\n\nexport enum LevelLength {\n Tiny = 0,\n Short = 1,\n Medium = 2,\n Long = 3,\n XL = 4,\n Platformer = 5,\n}\n\nexport enum LevelEpicRating {\n None = 0,\n Epic = 1,\n Legendary = 2,\n Mythic = 3,\n}\n\nexport enum LevelDemonDifficulty {\n Easy = 3,\n Medium = 4,\n Hard = 0,\n Insane = 5,\n Extreme = 6,\n}\n\nexport const levelSchema = z.object({\n /**\n * The id of the level\n */\n id: z.coerce.number().int(),\n /**\n * The name of the level\n */\n name: z.string(),\n /**\n * The level description\n */\n description: z.string().transform(val => Buffer.from(val, \"base64\").toString(\"utf-8\")),\n /**\n * The version of the level published\n */\n version: z.coerce.number().int(),\n /**\n * The player ID of the level author\n */\n playerId: z.coerce.number().int(),\n /**\n * Returns 0 if the level is N/A, returns 10 if a difficulty is assigned.\n *\n * @type {LevelDifficultyDenominator}\n */\n difficultyDenominator: z.coerce.number().int(),\n /**\n * The nominator used for calculating the level difficulty. Divided by the denominator to get the difficulty icon.\n *\n * Nowadays just 0 = unrated, 10 = easy, 20 = normal, 30 = hard, 40 = harder, 50 = insane.\n *\n * Can be also used to determine the demon difficulty as a side-effect of the voting system.\n *\n * @type {LevelDifficultyNumerator}\n */\n difficultyNumerator: z.coerce.number().int(),\n /**\n * The amount of times the level has been downloaded\n */\n downloads: z.coerce.number().int(),\n /**\n * The official song number used by the level, if applicable\n */\n officialSong: z.coerce.number().int().optional(),\n /**\n * The GD version the level was uploaded in.\n * Divide the version number by ten to get the correct number.\n */\n gameVersion: z.coerce\n .number()\n .int()\n .transform(val => {\n if (val === 1) {\n return 10;\n }\n if (val <= 7) {\n return val + 9;\n }\n if (val === 10) {\n return 17;\n }\n return val;\n }),\n /**\n * likes - dislikes\n */\n likes: z.coerce.number().int(),\n /**\n * A number from 0-4, where 0 is tiny and 4 is XL\n *\n * @type {LevelLength}\n */\n length: z.coerce.number().int(),\n /**\n * dislikes - likes\n */\n dislikes: z.coerce.number().int().optional(),\n /**\n * \tIf the level's difficulty is demon\n */\n demon: z.coerce.boolean(),\n /**\n * The amount of stars rewarded for completing the level\n */\n stars: z.coerce.number().int(),\n /**\n * 0 if the level is not featured, otherwise a positive number. The higher it is, the higher the level appears on the featured levels list.\n */\n featureScore: z.coerce.number().int(),\n /**\n * \tIf the level's difficulty is auto\n */\n auto: z.coerce.boolean(),\n /**\n * The ID the of the original level (if the level was copied)\n */\n copiedId: z.coerce.number().int(),\n /**\n * Whether the level uses two player mode\n */\n twoPlayer: z.coerce.boolean(),\n /**\n * The ID of the custom Newgrounds song used in the level\n */\n customSongId: z.coerce.number().int(),\n /**\n * The number of user coins placed in the level\n */\n coins: z.coerce.number().int(),\n /**\n * If the level's user coins are verified (silver)\n */\n verifiedCoins: z.coerce.boolean(),\n /**\n * The star value requested for the level\n */\n starsRequested: z.coerce.number().int(),\n /**\n * The epic rating for the level\n *\n * @type {LevelEpicRating}\n */\n epic: z.coerce.number().int(),\n /**\n * The difficulty of the demon rating. Can also be used to determine the level difficulty non-demons had before rating as a side-effect of the voting system.\n *\n * @type {LevelDemonDifficulty}\n */\n demonDifficulty: z.coerce.number().int(),\n /**\n * If the level is in a gauntlet\n */\n isGauntlet: z.coerce.boolean(),\n /**\n * The amount of objects in the level, used to determine if the level is considered \"large\". It caps at 65535\n */\n objects: z.coerce.number().int(),\n});\n\nexport type Level = z.infer<typeof levelSchema>;\n","import { z } from \"zod\";\n\nexport const listMappings = {\n 1: \"id\",\n 2: \"name\",\n 3: \"description\",\n 5: \"version\",\n 7: \"difficulty\",\n 10: \"downloads\",\n 14: \"likes\",\n 19: \"rated\",\n 28: \"uploadedAt\",\n 29: \"updatedAt\",\n 49: \"accountId\",\n 50: \"username\",\n 51: \"levels\",\n 55: \"reward\",\n 56: \"rewardRequirement\",\n};\n\nexport enum ListDifficulty {\n NA = -1,\n Auto = 0,\n Easy = 1,\n Normal = 2,\n Hard = 3,\n Harder = 4,\n Insane = 5,\n EasyDemon = 6,\n MediumDemon = 7,\n HardDemon = 8,\n InsaneDemon = 9,\n ExtremeDemon = 10,\n}\n\nexport const listSchema = z.object({\n /**\n * The id of the list\n */\n id: z.coerce.number().int(),\n /**\n * The name of the list\n */\n name: z.string(),\n /**\n * The list description\n */\n description: z.string().transform(val => Buffer.from(val, \"base64\").toString(\"utf-8\")),\n /**\n * The version of the list published\n */\n version: z.coerce.number().int(),\n /**\n * The difficulty of this list\n *\n * @type {ListDifficulty}\n */\n difficulty: z.coerce.number().int(),\n /**\n * The amount of times the list has been downloaded\n */\n downloads: z.coerce.number().int(),\n /**\n * likes - dislikes\n */\n likes: z.coerce.number().int(),\n /**\n * If the list is rated or not\n */\n rated: z.coerce.boolean(),\n /**\n * The timestamp of when the list was uploaded\n */\n uploadedAt: z.coerce.number().int(),\n /**\n * The timestamp of when the list was last updated\n */\n updatedAt: z.coerce.number().int(),\n /**\n * The account ID of the list author\n */\n accountId: z.coerce.number().int(),\n /**\n * The username of the list author\n */\n username: z.string(),\n /**\n * All level IDs in the list\n */\n levels: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int())),\n /**\n * The amount of diamonds awarded upon beating the required amount of levels in the list\n */\n reward: z.coerce.number().int(),\n /**\n * The amount of levels needed to claim the list reward\n */\n rewardRequirement: z.coerce.number().int(),\n});\n\nexport type List = z.infer<typeof listSchema>;\n","import { z } from \"zod\";\n\nexport const mapPacksMappings = {\n 1: \"id\",\n 2: \"name\",\n 3: \"levels\",\n 4: \"stars\",\n 5: \"coins\",\n 6: \"difficulty\",\n 7: \"textColor\",\n 8: \"barColor\",\n};\n\nexport enum MapPackDifficulty {\n Auto = 0,\n Easy = 1,\n Normal = 2,\n Hard = 3,\n Harder = 4,\n Insane = 5,\n HardDemon = 6,\n EasyDemon = 7,\n MediumDemon = 8,\n InsaneDemon = 9,\n ExtremeDemon = 10,\n}\n\nexport const mapPacksSchema = z.object({\n /**\n * The Map Pack ID\n */\n id: z.coerce.number().int(),\n /**\n * The Map Pack name\n */\n name: z.string(),\n /**\n * The level IDs\n */\n levels: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int())),\n /**\n * Stars given when completed\n */\n stars: z.coerce.number().int(),\n /**\n * Coins given when completed\n */\n coins: z.coerce.number().int(),\n /**\n * The Map Pack difficulty\n *\n * @type {MapPackDifficulty}\n */\n difficulty: z.coerce.number().int(),\n /**\n * The RGB color of the title text\n */\n textColor: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int()).length(3)),\n /**\n * The RGB color of the completion bar\n */\n barColor: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int()).length(3)),\n});\n\nexport type MapPack = z.infer<typeof mapPacksSchema>;\n","import { z } from \"zod\";\n\nexport const songMappings = {\n 1: \"id\",\n 2: \"name\",\n 3: \"artistId\",\n 4: \"artistName\",\n 5: \"size\",\n 6: \"videoId\",\n 7: \"youtubeURL\",\n 8: \"isVerified\",\n 9: \"songPriority\",\n 10: \"link\",\n 11: \"nong\",\n 12: \"extraArtistIds\",\n 13: \"new\",\n 14: \"newType\",\n 15: \"extraArtistNames\",\n};\n\nexport enum SongNong {\n None = 0,\n NCS = 1,\n}\n\nexport enum SongNewType {\n Yellow = 0,\n Blue = 1,\n}\n\nexport const songSchema = z.object({\n /**\n * The ID of the song on Newgrounds\n */\n id: z.coerce.number().int().optional(),\n /**\n * The name of the song\n */\n name: z.string(),\n /**\n * Newgrounds Artist ID\n */\n artistId: z.coerce.number().int(),\n /**\n * The name of the artist who made the song\n */\n artistName: z.string(),\n /**\n * Size of the song in MB, rounded to two decimal places\n */\n size: z.coerce.number(),\n /**\n * The Video ID for the songs YouTube Video\n */\n videoId: z.string().optional(),\n /**\n * The URL of the newgrounds user's youtube channel\n */\n youtubeURL: z.string().optional(),\n /**\n * If the song artist is scouted on newgrounds\n */\n isVerified: z.coerce.boolean(),\n /**\n * Priority over the song list\n */\n songPriority: z.coerce.number().int().optional(),\n /**\n * Link to the song's mp3\n */\n link: z.string().transform(val => decodeURIComponent(val)),\n /**\n * Type of NONG (Not on Newgrounds)\n *\n * @type {SongNong}\n */\n nong: z.coerce.number().int().optional(),\n /**\n * IDs of extra artists\n */\n extraArtistIds: z\n .string()\n .transform(val => val.split(\".\"))\n .pipe(z.array(z.coerce.number().int()))\n .optional(),\n /**\n * Whether the NEW icon shows up or not\n */\n new: z.coerce.boolean(),\n /**\n * Type of NEW icon. 0 for Yellow, 1 for Blue\n *\n * @type {SongNewType}\n */\n newType: z.coerce.number().int().optional(),\n /**\n * Artist names in the format [id, name][]\n */\n extraArtistNames: z\n .string()\n .transform(val => {\n const result = [];\n const elements = val.split(\",\");\n for (let i = 0; i < elements.length; i += 2) {\n result.push(elements.slice(i, i + 2));\n }\n return result;\n })\n .pipe(z.array(z.tuple([z.coerce.number().int(), z.string()])))\n .optional(),\n});\n\nexport type Song = z.infer<typeof songSchema>;\n","import { z } from \"zod\";\n\nexport const userMappings = {\n 1: \"username\",\n 2: \"id\",\n 3: \"stars\",\n 4: \"totalDemons\",\n 6: \"ranking\",\n 7: \"accountHighlight\",\n 8: \"creatorPoints\",\n 9: \"iconId\",\n 10: \"primaryColor\",\n 11: \"secondaryColor\",\n 13: \"secretCoins\",\n 14: \"iconType\",\n 15: \"special\",\n 16: \"accountId\",\n 17: \"userCoins\",\n 18: \"messageState\",\n 19: \"friendsState\",\n 20: \"youtube\",\n 21: \"accIcon\",\n 22: \"accShip\",\n 23: \"accBall\",\n 24: \"accBird\",\n 25: \"accDart\",\n 26: \"accRobot\",\n 28: \"accGlow\",\n 29: \"isRegistered\",\n 30: \"globalRank\",\n 42: \"age\",\n 43: \"accSpider\",\n 44: \"twitter\",\n 45: \"twitch\",\n 46: \"diamonds\",\n 48: \"accExplosion\",\n 49: \"moderatorLevel\",\n 50: \"commentHistoryState\",\n 51: \"glowColor\",\n 52: \"moons\",\n 53: \"accSwing\",\n 54: \"accJetpack\",\n 55: \"demons\",\n 56: \"classicLevels\",\n 57: \"platformerLevels\",\n};\n\nexport enum UserMessageState {\n All = 0,\n FriendsOnly = 1,\n None = 2,\n}\n\nexport enum UserFriendsState {\n All = 0,\n None = 1,\n}\n\nexport enum UserCommentHistoryState {\n All = 0,\n FriendsOnly = 1,\n None = 2,\n}\n\nexport enum UserModeratorLevel {\n None = 0,\n Moderator = 1,\n ElderModerator = 2,\n}\n\nexport const userSchema = z.object({\n /**\n * The name of player\n */\n username: z.string(),\n /**\n * The ID of player\n */\n id: z.coerce.number().int(),\n /**\n * The count of stars player have\n */\n stars: z.coerce.number().int(),\n /**\n * The count of diamonds player have\n */\n diamonds: z.coerce.number().int().optional(),\n /**\n * The amount of moons the player have\n */\n moons: z.coerce.number().int(),\n /**\n * The count of coins the player have\n */\n secretCoins: z.coerce.number().int(),\n /**\n * The count of usercoins player have\n */\n userCoins: z.coerce.number().int(),\n /**\n * First color of the player\n */\n primaryColor: z.coerce.number().int(),\n /**\n * Second color of the player\n */\n secondaryColor: z.coerce.number().int(),\n /**\n * Glow color of the player\n */\n glowColor: z.coerce.number().int().optional(),\n /**\n * The special number of the player\n */\n special: z.coerce.number().int().optional(),\n /**\n * The account ID of the player\n */\n accountId: z.coerce.number().int(),\n /**\n * @type {UserMessageState}\n */\n messageState: z.coerce.number().int().optional(),\n /**\n * @type {UserFriendsState}\n */\n friendsState: z.coerce.number().int().optional(),\n /**\n * The time since the last levelScore submit\n */\n age: z.string().optional(),\n /**\n * @type {UserModeratorLevel}\n */\n moderatorLevel: z.coerce.number().int().optional(),\n /**\n * @type {UserCommentHistoryState}\n */\n commentHistoryState: z.coerce.number().int().optional(),\n /**\n * If an account is registered or not\n */\n isRegistered: z.coerce.boolean().optional(),\n /**\n * The global rank of this player\n */\n globalRank: z.coerce.number().int().optional(),\n /**\n * The global leaderboard position of the player\n */\n ranking: z.coerce.number().int().optional(),\n /**\n * The count of creatorpoints player have\n */\n creatorPoints: z.coerce.number().int(),\n /**\n * The count of demons player have\n */\n totalDemons: z.coerce.number().int(),\n /**\n * Breakdown of the player's demons, in the format\n * `{easy},{medium},{hard},{insane},{extreme},{easyPlatformer},{mediumPlatformer},{hardPlatformer},{insanePlatformer},{extremePlatformer},{weekly},{gauntlet}`\n */\n demons: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int()))\n .optional(),\n /**\n * Breakdown of the player's classic mode non-demons, in the format\n * `{auto},{easy},{normal},{hard},{harder},{insane},{daily},{gauntlet}`\n */\n classicLevels: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int()))\n .optional(),\n /**\n * Breakdown of the player's platformer mode non-demons, in the format\n * `{auto},{easy},{normal},{hard},{harder},{insane}`\n */\n platformerLevels: z\n .string()\n .transform(val => val.split(\",\"))\n .pipe(z.array(z.coerce.number().int()))\n .optional(),\n /**\n * The youtube url of the player\n */\n youtube: z.coerce.string().optional(),\n /**\n * The twitter of the player\n */\n twitter: z.coerce.string().optional(),\n /**\n * The twitch of the player\n */\n twitch: z.coerce.string().optional(),\n iconId: z.coerce.number().int().optional(),\n /**\n * The iconType of the player\n */\n iconType: z.coerce.number().int().optional(),\n /**\n * The icon number of the player\n */\n accIcon: z.coerce.number().int().optional(),\n /**\n * The ship number of the player\n */\n accShip: z.coerce.number().int().optional(),\n /**\n * The ball number of the player\n */\n accBall: z.coerce.number().int().optional(),\n /**\n * The bird number of the player\n */\n accBird: z.coerce.number().int().optional(),\n /**\n * The dart (wave) number of the player\n */\n accDart: z.coerce.number().int().optional(),\n /**\n * The robot number of the player\n */\n accRobot: z.coerce.number().int().optional(),\n /**\n * The glow number of the player\n */\n accGlow: z.coerce.number().int().optional(),\n /**\n * The swing number of the player\n */\n accSwing: z.coerce.number().int().optional(),\n /**\n * The jetpack number of the player\n */\n accJetpack: z.coerce.number().int().optional(),\n /**\n * The spider number of the player\n */\n accSpider: z.coerce.number().int().optional(),\n /**\n * The explosion number of the player\n */\n accExplosion: z.coerce.number().int().optional(),\n /**\n * The accountID of the player. Is used for highlighting the player on the leaderboards\n */\n accountHighlight: z.coerce.number().int().optional(),\n});\n\nexport type User = z.infer<typeof userSchema>;\n","export class APIError extends Error {\n public constructor(\n message: string,\n options?: ErrorOptions | undefined,\n public response?: Response | null,\n ) {\n super(message, options);\n this.response = response || null;\n }\n}\n","export const BOOMLINGS_URL = \"https://www.boomlings.com\";\n\nexport const GEOMETRY_DASH_URL = \"https://www.geometrydash.com\";\n\nexport const SFX_LIBRARY_VERSION_URL = \"https://geometrydashfiles.b-cdn.net/sfx/sfxlibrary_version.txt\";\n\nexport const MUSIC_LIBRARY_VERSION_URL = \"https://geometrydashfiles.b-cdn.net/music/musiclibrary_version_02.txt\";\n","import { z } from \"zod\";\nimport {\n parseGroups,\n parseObject,\n parseObjectList,\n parseSong,\n parseSongList,\n parseTuple,\n parseTupleList,\n} from \"./parser\";\nimport { gauntletMappings, gauntletSchema } from \"./resources/gauntlets\";\nimport { levelMappings, levelSchema } from \"./resources/levels\";\nimport { listMappings, listSchema } from \"./resources/lists\";\nimport { mapPacksMappings, mapPacksSchema } from \"./resources/mapPacks\";\nimport { Song, songMappings, songSchema } from \"./resources/songs\";\nimport { User, userMappings, userSchema } from \"./resources/users\";\nimport { REST } from \"./REST\";\nimport { COMMON_SECRET } from \"./secrets\";\nimport { MUSIC_LIBRARY_VERSION_URL, SFX_LIBRARY_VERSION_URL } from \"./constants\";\nimport { GetUserLeaderboardOptions, SearchLevelsOptions, SearchListsOptions } from \"./requests\";\nimport { DailyLevel, GauntletsData, LevelsData, ListsData, MapPacksData } from \"./responses\";\n\nconst dailyOrWeeklySchema = z.tuple([z.coerce.number().int()]);\nconst paginationSchema = z.tuple([z.coerce.number().int(), z.coerce.number().int(), z.coerce.number().int()]);\nconst creatorSchema = z.tuple([z.coerce.number().int(), z.string(), z.coerce.number().int()]);\nconst versionSchema = z.coerce.number().int();\n\n/**\n * The client to interact with the Geometry Dash API\n */\nexport class GDAPI {\n public readonly rest: REST;\n\n public constructor() {\n this.rest = new REST();\n }\n\n public async getDailyLevel(): Promise<DailyLevel> {\n const data = await this.rest.post(\"/database/getGJDailyLevel.php\", {\n secret: COMMON_SECRET,\n weekly: \"0\",\n });\n\n const result = parseTupleList(data, dailyOrWeeklySchema);\n\n return {\n index: result[0][0],\n timeLeft: result[1][0],\n };\n }\n\n // TODO: this. Currently returns the same as the daily level, for some reasons\n /*public async getWeeklyLevel(): Promise<WeeklyLevel> {\n const data = await this.rest.post(\"/database/getGJDailyLevel.php\", {\n secret: COMMON_SECRET,\n weekly: \"1\",\n });\n\n const result = parseTupleList(data, dailyOrWeeklySchema);\n\n return {\n index: result[0][0],\n timeLeft: result[1][0],\n };\n }*/\n\n public async getCurrentSFXLibraryVersion(): Promise<number> {\n const res = await fetch(SFX_LIBRARY_VERSION_URL);\n const data = await res.text();\n const version = versionSchema.parse(data);\n\n return version;\n }\n\n public async getCurrentMusicLibraryVersion(): Promise<number> {\n const res = await fetch(MUSIC_LIBRARY_VERSION_URL);\n const data = await res.text();\n const version = versionSchema.parse(data);\n\n return version;\n }\n\n public async getGauntlets(): Promise<GauntletsData> {\n const data = await this.rest.post(\"/database/getGJGauntlets21.php\", {\n secret: COMMON_SECRET,\n special: \"1\",\n });\n\n const [rawGauntlets, hash] = parseGroups(data, 2);\n const gauntlets = parseObjectList(rawGauntlets, gauntletMappings, gauntletSchema);\n\n return {\n gauntlets,\n hash,\n };\n }\n\n /**\n * @example\n * ```ts\n * searchLevels({\n * type: SearchLevelsType.Query,\n * query: \"bloodbath\"\n * });\n * ```\n */\n public async searchLevels(options: SearchLevelsOptions): Promise<LevelsData> {\n const requestOptions: Record<string, string> = {\n secret: COMMON_SECRET,\n type: options.type.toString(),\n };\n if (options.page !== undefined) requestOptions.page = options.page.toString();\n if (options.query !== undefined) requestOptions.str = options.query;\n if (options.gauntlet !== undefined) requestOptions.gauntlet = options.gauntlet.toString();\n if (options.difficulty !== undefined) requestOptions.diff = options.difficulty.toString();\n if (options.demonFilter !== undefined) requestOptions.demonFilter = options.demonFilter.toString();\n if (options.length !== undefined) requestOptions.len = options.length.toString();\n if (options.featured !== undefined) requestOptions.featured = options.featured ? \"1\" : \"0\";\n if (options.original !== undefined) requestOptions.original = options.original ? \"1\" : \"0\";\n if (options.twoPlayer !== undefined) requestOptions.twoPlayer = options.twoPlayer ? \"1\" : \"0\";\n if (options.coins !== undefined) requestOptions.coins = options.coins ? \"1\" : \"0\";\n if (options.epic !== undefined) requestOptions.epic = options.epic ? \"1\" : \"0\";\n if (options.legendary !== undefined) requestOptions.legendary = options.legendary ? \"1\" : \"0\";\n if (options.mythic !== undefined) requestOptions.mythic = options.mythic ? \"1\" : \"0\";\n if (options.noStar !== undefined) requestOptions.noStar = options.noStar ? \"1\" : \"0\";\n if (options.star !== undefined) requestOptions.star = options.star ? \"1\" : \"0\";\n if (options.song !== undefined) requestOptions.song = options.song.toString();\n if (options.customSong !== undefined) requestOptions.customSong = options.customSong.toString();\n\n const data = await this.rest.post(\"/database/getGJLevels21.php\", requestOptions);\n\n const [rawLevels, rawCreators, rawSongs, rawPagination, hash] = parseGroups(data, 5);\n const levels = parseObjectList(rawLevels, levelMappings, levelSchema);\n const creators = parseTupleList(rawCreators, creatorSchema);\n const songs = rawSongs ? parseSongList(rawSongs, songMappings, songSchema) : [];\n const pagination = parseTuple(rawPagination, paginationSchema);\n\n return {\n levels,\n creators: creators.map(c => ({\n userId: c[0],\n username: c[1],\n accountId: c[2],\n })),\n songs,\n page: {\n total: pagination[0],\n offset: pagination[1],\n amount: pagination[2],\n },\n hash,\n };\n }\n\n /**\n * @example\n * ```ts\n * searchLists({\n * type: SearchListType.Query,\n * query: \"Name\"\n * });\n * ```\n */\n public async searchLists(options: SearchListsOptions): Promise<ListsData> {\n const requestOptions: Record<string, string> = {\n secret: COMMON_SECRET,\n type: options.type.toString(),\n };\n if (options.page !== undefined) requestOptions.page = options.page.toString();\n if (options.query !== undefined) requestOptions.str = options.query;\n if (options.difficulty !== undefined) requestOptions.diff = options.difficulty.toString();\n if (options.demonFilter !== undefined) requestOptions.demonFilter = options.demonFilter.toString();\n if (options.rated !== undefined) requestOptions.rated = options.rated ? \"1\" : \"0\";\n\n const data = await this.rest.post(\"/database/getGJLevelLists.php\", requestOptions);\n\n const [rawLists, rawCreators, rawPagination, hash] = parseGroups(data, 4);\n const lists = parseObjectList(rawLists, listMappings, listSchema);\n const creators = parseTupleList(rawCreators, creatorSchema);\n const pagination = parseTuple(rawPagination, paginationSchema);\n\n return {\n lists,\n creators: creators.map(c => ({\n userId: c[0],\n username: c[1],\n accountId: c[2],\n })),\n page: {\n total: pagination[0],\n offset: pagination[1],\n amount: pagination[2],\n },\n hash,\n };\n }\n\n /**\n * @param page - Starts at 0\n */\n public async getMapPacks(page = 0): Promise<MapPacksData> {\n const data = await this.rest.post(\"/database/getGJMapPacks21.php\", {\n secret: COMMON_SECRET,\n page: page.toString(),\n });\n\n const [rawPacks, rawPagination, hash] = parseGroups(data, 3);\n const packs = parseObjectList(rawPacks, mapPacksMappings, mapPacksSchema);\n const pagination = parseTuple(rawPagination, paginationSchema);\n\n return {\n packs,\n page: {\n total: pagination[0],\n offset: pagination[1],\n amount: pagination[2],\n },\n hash,\n };\n }\n\n public async getSongById(songId: string): Promise<Song> {\n const data = await this.rest.post(\"/database/getGJSongInfo.php\", {\n secret: COMMON_SECRET,\n songID: songId,\n });\n\n return parseSong(data, songMappings, songSchema);\n }\n\n public async getUserById(accountId: number): Promise<User> {\n const data = await this.rest.post(\"/database/getGJUserInfo20.php\", {\n secret: COMMON_SECRET,\n targetAccountID: accountId.toString(),\n });\n\n return parseObject(data, userMappings, userSchema);\n }\n\n public async getUserByName(name: string): Promise<User> {\n const data = await this.rest.post(\"/database/getGJUsers20.php\", {\n secret: COMMON_SECRET,\n str: name,\n });\n\n const [rawUser] = parseGroups(data, 2);\n\n return parseObject(rawUser, userMappings, userSchema);\n }\n\n public async getUserLeaderboard(options?: GetUserLeaderboardOptions): Promise<User[]> {\n const requestOptions: Record<string, string> = {\n secret: COMMON_SECRET,\n type: options?.type || \"top\",\n };\n if (options?.count !== undefined) requestOptions.count = options.count.toString();\n\n const data = await this.rest.post(\"/database/getGJScores20.php\", requestOptions);\n\n // The data ends with `|`\n const realData = data.slice(0, -1);\n\n return parseObjectList(realData, userMappings, userSchema);\n }\n}\n","import { z } from \"zod\";\n\n/**\n * Threw when the GD response data could not be parsed\n */\nexport class ParseError extends Error {}\n\n/**\n * Parse a GD object in the format `key:value:key:value`\n */\nexport const parseRawObject = (data: string): [string, string][] => {\n const elements = data.split(\":\");\n if (elements.length % 2 !== 0)\n throw new ParseError(`Invalid GD object, got ${elements.length} elements. [${data}]`);\n\n const props: [string, string][] = [];\n\n for (let i = 0; i < elements.length; i += 2) {\n const key = elements[i];\n const value = elements[i + 1];\n\n props.push([key, value]);\n }\n\n return props;\n};\n\n/**\n * Parse and validate a GD object in the format `key:value:key:value`\n */\nexport const parseObject = <T extends z.AnyZodObject>(\n data: string,\n mappings: Record<number, string>,\n schema: T,\n): z.infer<T> => {\n const entries = parseRawObject(data);\n const object: Record<string, string> = {};\n\n for (const [key, value] of entries) {\n if (!(key in mappings)) continue;\n object[mappings[+key]] = value;\n }\n\n return schema.parse(object);\n};\n\n/**\n * Parse and validate a GD tuple list in the format `value:value:value|value:value:value`\n */\nexport const parseTupleList = <T extends z.AnyZodTuple>(list: string, schema: T): z.infer<T>[] => {\n const rawTuples = list.split(\"|\");\n const tuples = [];\n\n for (const rawTuple of rawTuples) {\n const tuple = parseTuple(rawTuple, schema);\n tuples.push(tuple);\n }\n\n return tuples;\n};\n\n/**\n * Parse and validate a GD object list in the format `<object>|<object>`\n */\nexport const parseObjectList = <T extends z.AnyZodObject>(\n list: string,\n mappings: Record<number, string>,\n schema: T,\n): z.infer<T>[] => {\n const rawObjects = list.split(\"|\");\n const objects = [];\n\n for (const rawObject of rawObjects) {\n const object = parseObject(rawObject, mappings, schema);\n objects.push(object);\n }\n\n return objects;\n};\n\n/**\n * Parse and validate a GD tuple in the format `value:value:value`\n */\nexport const parseTuple = <T extends z.AnyZodTuple>(data: string, schema: T): z.infer<T> => {\n const rawTuple = data.split(\":\");\n return schema.parse(rawTuple);\n};\n\n/**\n * Parse a GD groups in the format `data#data#data`\n * @param count - The expected group count\n */\nexport const parseGroups = (data: string, count: number): string[] => {\n const groups = data.split(\"#\");\n\n if (groups.length !== count) {\n throw new ParseError(`Invalid group count, expected ${count} but got ${groups.length}`);\n }\n\n return groups;\n};\n\n/**\n * Parse a GD song in the format `key~|~value~|~key~|~value`\n */\nexport const parseRawSong = (data: string): [string, string][] => {\n const elements = `~${data}~`.split(\"|\");\n if (elements.length % 2 !== 0)\n throw new ParseError(`Invalid GD object, got ${elements.length} elements. [${data}]`);\n\n const props: [string, string][] = [];\n\n for (let i = 0; i < elements.length; i += 2) {\n const key = elements[i].slice(1, -1);\n const value = elements[i + 1].slice(1, -1);\n\n props.push([key, value]);\n }\n\n return props;\n};\n\n/**\n * Parse and validate a GD song in the format `key~|~value~|~key~|~value`\n */\nexport const parseSong = <T extends z.AnyZodObject>(\n data: string,\n mappings: Record<number, string>,\n schema: T,\n): z.infer<T> => {\n const entries = parseRawSong(data);\n const object: Record<string, string> = {};\n\n for (const [key, value] of entries) {\n if (!(key in mappings)) continue;\n object[mappings[+key]] = value;\n }\n\n return schema.parse(object);\n};\n\n/**\n * Parse and validate a GD song list in the format `<song>:<song>`\n */\nexport const parseSongList = <T extends z.AnyZodObject>(\n list: string,\n mappings: Record<number, string>,\n schema: T,\n): z.infer<T>[] => {\n const rawSongs = list.split(\":\");\n const songs = [];\n\n for (const rawSong of rawSongs) {\n const song = parseSong(rawSong, mappings, schema);\n songs.push(song);\n }\n\n return songs;\n};\n","import { APIError } from \"./APIError\";\nimport { BOOMLINGS_URL } from \"./constants\";\n\n/**\n * Use to interact with the Geometry Dash API.\n *\n * @see https://wyliemaster.github.io/gddocs/#/endpoints/generic\n */\nexport class REST {\n /**\n * Throws {@link APIError} if the request fail\n * \n * @param path - Must start with `/`\n */\n public async request(method: string, path: string, body?: Record<string, string>): Promise<Response> {\n if (!path.startsWith(\"/\")) {\n throw new Error(`Invalid path: ${path}`);\n }\n\n const url = `${BOOMLINGS_URL}${path}`;\n const encodedBody = body ? new URLSearchParams(body).toString() : undefined;\n const headers = new Headers({\n \"User-Agent\": \"\",\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n });\n\n let res;\n try {\n res = await fetch(url, { method, headers, body: encodedBody });\n } catch (err) {\n throw new APIError(`Failed to fetch ${url}`, { cause: err });\n }\n\n if (!res.ok) {\n throw new APIError(`Invalid response from ${url}: ${res.statusText} (Code: ${res.status})`, undefined, res);\n }\n\n return res;\n }\n\n public async post(path: string, body?: Record<string, string>): Promise<string> {\n const res = await this.request(\"POST\", path, body);\n const text = await res.text();\n\n if (text.length <= 3 && text.startsWith(\"-\")) {\n throw new APIError(`Invalid request (Error code: ${text})`, undefined, res);\n }\n\n return text;\n }\n}\n","export const COMMON_SECRET = \"Wmfd2893gb7\";\n","import { LevelLength } from \"./resources/levels\";\n\nexport interface SearchLevelsOptions {\n type: SearchLevelsType;\n /**\n * Which page to request, defaults to 0\n */\n page?: number;\n /**\n * Search query, user ID or level list depending on type\n *\n * Only valid on types `Query` and `UserLists`\n */\n query?: string;\n /**\n * The ID for the gauntlet being requested\n */\n gauntlet?: number;\n /**\n * Difficulty filter\n */\n difficulty?: SearchListsDifficulty;\n /**\n * Selects which demon difficulty to search. If not present, it will search all demon types\n */\n demonFilter?: SearchListsDemonFilter;\n /**\n * Level length\n */\n length?: LevelLength;\n /**\n * Featured filter\n */\n featured?: boolean;\n /**\n * Original filter\n */\n original?: boolean;\n /**\n * Two players filter\n */\n twoPlayer?: boolean;\n /**\n * Coins filter\n */\n coins?: boolean;\n /**\n * Epic filter\n */\n epic?: boolean;\n /**\n * Legendary filter\n */\n legendary?: boolean;\n /**\n * Mythic filter\n */\n mythic?: boolean;\n /**\n * Unrated filter\n */\n noStar?: boolean;\n /**\n * Rated filter\n */\n star?: boolean;\n /**\n * Official (or custom) song ID, not sent when off\n */\n song?: number;\n /**\n * Newgrounds song, 1 when on and uses song as the ID, not sent when off\n */\n customSong?: number;\n}\n\nexport enum SearchLevelsType {\n Query = 0,\n MostDownloaded = 1,\n MostLiked = 2,\n Trending = 3,\n Recent = 4,\n UserLevels = 5,\n Featured = 6,\n Magic = 7,\n ModeratorSentLevels = 8,\n Awarded = 11,\n MostLikedInGDWorld = 15,\n HallOfFame = 16,\n FeaturedInGDWorld = 17,\n DailyHistory = 21,\n WeeklyHistory = 22,\n LevelList = 25,\n}\n\nexport enum SearchLevelsDifficulty {\n NA = -1,\n Demons = -2,\n Easy = 1,\n Normal = 2,\n Hard = 3,\n Harder = 4,\n Insane = 5,\n}\n\nexport enum SearchLevelsDemonFilter {\n EasyDemon = 1,\n MediumDemon = 2,\n HardDemon = 3,\n InsaneDemon = 4,\n ExtremeDemon = 5,\n}\n\nexport interface SearchListsOptions {\n type: SearchListsType;\n /**\n * Which page to request, defaults to 0\n */\n page?: number;\n /**\n * Search query, user ID or level list depending on type\n *\n * Only valid on types `Query` and `UserLists`\n */\n query?: string;\n /**\n * Difficulty filter\n */\n difficulty?: SearchListsDifficulty;\n /**\n * Selects which demon difficulty to search. If not present, it will search all demon types\n */\n demonFilter?: SearchListsDemonFilter;\n /**\n * Rated filter\n */\n rated?: boolean;\n}\n\nexport enum SearchListsType {\n Query = 0,\n MostDownloaded = 1,\n MostLiked = 2,\n Trending = 3,\n Recent = 4,\n UserLists = 5,\n Awarded = 11,\n SentLists = 27,\n}\n\nexport enum SearchListsDifficulty {\n NA = -1,\n Demons = -2,\n Easy = 1,\n Normal = 2,\n Hard = 3,\n Harder = 4,\n Insane = 5,\n}\n\nexport enum SearchListsDemonFilter {\n EasyDemon = 1,\n MediumDemon = 2,\n HardDemon = 3,\n InsaneDemon = 4,\n ExtremeDemon = 5,\n}\n\nexport interface GetUserLeaderboardOptions {\n type?: \"top\" | \"creators\";\n /**\n * Limited to 100\n */\n count?: number;\n}\n","/**\n * @deprecated The version will not be exported in the next major version.\n */\nexport const version = \"0.0.0\";\n\nexport * from \"./resources/gauntlets\";\nexport * from \"./resources/levels\";\nexport * from \"./resources/lists\";\nexport * from \"./resources/mapPacks\";\nexport * from \"./resources/songs\";\nexport * from \"./resources/users\";\nexport * from \"./APIError\";\nexport * from \"./constants\";\nexport * from \"./GDAPI\";\nexport * from \"./parser\";\nexport * from \"./requests\";\nexport * from \"./responses\";\nexport * from \"./REST\";\nexport * from \"./secrets\";\n"],"mappings":"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