ytmusic-api-proxy
Version:
YouTube Music API
1 lines • 162 kB
Source Map (JSON)
{"version":3,"sources":["../src/YTMusic.ts","../src/constants.ts","../src/types.ts","../node_modules/zod-to-json-schema/dist/esm/Options.js","../node_modules/zod-to-json-schema/dist/esm/Refs.js","../node_modules/zod-to-json-schema/dist/esm/errorMessages.js","../node_modules/zod-to-json-schema/dist/esm/getRelativePath.js","../node_modules/zod-to-json-schema/dist/esm/selectParser.js","../node_modules/zod-to-json-schema/dist/esm/parsers/any.js","../node_modules/zod-to-json-schema/dist/esm/parsers/array.js","../node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js","../node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js","../node_modules/zod-to-json-schema/dist/esm/parsers/branded.js","../node_modules/zod-to-json-schema/dist/esm/parsers/catch.js","../node_modules/zod-to-json-schema/dist/esm/parsers/date.js","../node_modules/zod-to-json-schema/dist/esm/parsers/default.js","../node_modules/zod-to-json-schema/dist/esm/parsers/effects.js","../node_modules/zod-to-json-schema/dist/esm/parsers/enum.js","../node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js","../node_modules/zod-to-json-schema/dist/esm/parsers/literal.js","../node_modules/zod-to-json-schema/dist/esm/parsers/record.js","../node_modules/zod-to-json-schema/dist/esm/parsers/string.js","../node_modules/zod-to-json-schema/dist/esm/parsers/map.js","../node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js","../node_modules/zod-to-json-schema/dist/esm/parsers/never.js","../node_modules/zod-to-json-schema/dist/esm/parsers/null.js","../node_modules/zod-to-json-schema/dist/esm/parsers/union.js","../node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js","../node_modules/zod-to-json-schema/dist/esm/parsers/number.js","../node_modules/zod-to-json-schema/dist/esm/parsers/object.js","../node_modules/zod-to-json-schema/dist/esm/parsers/optional.js","../node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js","../node_modules/zod-to-json-schema/dist/esm/parsers/promise.js","../node_modules/zod-to-json-schema/dist/esm/parsers/set.js","../node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js","../node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js","../node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js","../node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js","../node_modules/zod-to-json-schema/dist/esm/parseDef.js","../node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js","../src/utils/checkType.ts","../src/utils/traverse.ts","../src/utils/filters.ts","../src/parsers/PlaylistParser.ts","../src/parsers/Parser.ts","../src/parsers/SongParser.ts","../src/parsers/AlbumParser.ts","../src/parsers/VideoParser.ts","../src/parsers/ArtistParser.ts","../src/parsers/SearchParser.ts","../src/index.ts"],"sourcesContent":["import axios, { AxiosInstance } from \"axios\"\nimport { Cookie, CookieJar } from \"tough-cookie\"\nimport { HttpsProxyAgent } from \"https-proxy-agent\"\nimport { SocksProxyAgent } from \"socks-proxy-agent\"\n\nimport { FE_MUSIC_HOME } from \"./constants\"\nimport AlbumParser from \"./parsers/AlbumParser\"\nimport ArtistParser from \"./parsers/ArtistParser\"\nimport Parser from \"./parsers/Parser\"\nimport PlaylistParser from \"./parsers/PlaylistParser\"\nimport SearchParser from \"./parsers/SearchParser\"\nimport SongParser from \"./parsers/SongParser\"\nimport VideoParser from \"./parsers/VideoParser\"\nimport {\n\tAlbumDetailed,\n\tAlbumFull,\n\tArtistDetailed,\n\tArtistFull,\n\tHomeSection,\n\tPlaylistDetailed,\n\tPlaylistFull,\n\tProxyConfig,\n\tSearchResult,\n\tSongDetailed,\n\tSongFull,\n\tUpNextsDetails,\n\tVideoDetailed,\n\tVideoFull,\n\tYTMusicOptions,\n} from \"./types\"\nimport { traverse, traverseList, traverseString } from \"./utils/traverse\"\n\naxios.defaults.headers.common[\"Accept-Encoding\"] = \"gzip\"\n\nexport default class YTMusic {\n\tprivate cookiejar: CookieJar\n\tprivate config?: Record<string, string>\n\tprivate client: AxiosInstance\n\tprivate proxyConfig?: ProxyConfig | undefined\n\n\t/**\n\t * Creates an instance of YTMusic\n\t * Make sure to call initialize()\n\t * @param proxyConfig - Optional proxy configuration\n\t */\n\tpublic constructor(proxyConfig?: ProxyConfig | undefined) {\n\t\tthis.cookiejar = new CookieJar()\n\t\tthis.config = {}\n\t\tthis.proxyConfig = proxyConfig\n\n\t\tconst axiosConfig: any = {\n\t\t\tbaseURL: \"https://music.youtube.com/\",\n\t\t\theaders: {\n\t\t\t\t\"User-Agent\":\n\t\t\t\t\t\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36\",\n\t\t\t\t\"Accept-Language\": \"en-US,en;q=0.5\",\n\t\t\t},\n\t\t\twithCredentials: true,\n\t\t}\n\n\t\t// Configure proxy if provided\n\t\tif (this.proxyConfig) {\n\t\t\tconst { protocol = \"http\", host, port, auth } = this.proxyConfig\n\t\t\tlet proxyUrl = `${protocol}://`\n\t\t\t\n\t\t\tif (auth) {\n\t\t\t\tproxyUrl += `${auth.username}:${auth.password}@`\n\t\t\t}\n\t\t\t\n\t\t\tproxyUrl += `${host}:${port}`\n\n\t\t\tif (protocol === \"socks4\" || protocol === \"socks5\") {\n\t\t\t\taxiosConfig.httpsAgent = new SocksProxyAgent(proxyUrl)\n\t\t\t\taxiosConfig.httpAgent = new SocksProxyAgent(proxyUrl)\n\t\t\t} else {\n\t\t\t\taxiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl)\n\t\t\t\taxiosConfig.httpAgent = new HttpsProxyAgent(proxyUrl)\n\t\t\t}\n\t\t}\n\n\t\tthis.client = axios.create(axiosConfig)\n\n\t\tthis.client.interceptors.request.use(req => {\n\t\t\tif (req.baseURL) {\n\t\t\t\tconst cookieString = this.cookiejar.getCookieStringSync(req.baseURL)\n\t\t\t\tif (cookieString) {\n\t\t\t\t\treq.headers[\"cookie\"] = cookieString\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn req\n\t\t})\n\n\t\tthis.client.interceptors.response.use(res => {\n\t\t\tif (res.headers && res.config.baseURL) {\n\t\t\t\tconst cookieStrings = res.headers[\"set-cookie\"] || []\n\t\t\t\tfor (const cookieString of cookieStrings) {\n\t\t\t\t\tconst cookie = Cookie.parse(cookieString)\n\t\t\t\t\tif (cookie) {\n\t\t\t\t\t\tthis.cookiejar.setCookieSync(cookie, res.config.baseURL)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn res\n\t\t})\n\t}\n\n\t/**\n\t * Initializes the API\n\t */\n\tpublic async initialize(options?: YTMusicOptions) {\n\t\tconst { cookies, GL, HL, proxy } = options ?? {}\n\n\t\t// Update proxy configuration if provided in initialize\n\t\tif (proxy && !this.proxyConfig) {\n\t\t\tthis.proxyConfig = proxy\n\t\t\t// Recreate client with proxy configuration\n\t\t\tconst axiosConfig: any = {\n\t\t\t\tbaseURL: \"https://music.youtube.com/\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"User-Agent\":\n\t\t\t\t\t\t\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36\",\n\t\t\t\t\t\"Accept-Language\": \"en-US,en;q=0.5\",\n\t\t\t\t},\n\t\t\t\twithCredentials: true,\n\t\t\t}\n\n\t\t\tconst { protocol = \"http\", host, port, auth } = proxy\n\t\t\tlet proxyUrl = `${protocol}://`\n\t\t\t\n\t\t\tif (auth) {\n\t\t\t\tproxyUrl += `${auth.username}:${auth.password}@`\n\t\t\t}\n\t\t\t\n\t\t\tproxyUrl += `${host}:${port}`\n\n\t\t\tif (protocol === \"socks4\" || protocol === \"socks5\") {\n\t\t\t\taxiosConfig.httpsAgent = new SocksProxyAgent(proxyUrl)\n\t\t\t\taxiosConfig.httpAgent = new SocksProxyAgent(proxyUrl)\n\t\t\t} else {\n\t\t\t\taxiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl)\n\t\t\t\taxiosConfig.httpAgent = new HttpsProxyAgent(proxyUrl)\n\t\t\t}\n\n\t\t\tthis.client = axios.create(axiosConfig)\n\n\t\t\t// Re-add interceptors\n\t\t\tthis.client.interceptors.request.use(req => {\n\t\t\t\tif (req.baseURL) {\n\t\t\t\t\tconst cookieString = this.cookiejar.getCookieStringSync(req.baseURL)\n\t\t\t\t\tif (cookieString) {\n\t\t\t\t\t\treq.headers[\"cookie\"] = cookieString\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn req\n\t\t\t})\n\n\t\t\tthis.client.interceptors.response.use(res => {\n\t\t\t\tif (res.headers && res.config.baseURL) {\n\t\t\t\t\tconst cookieStrings = res.headers[\"set-cookie\"] || []\n\t\t\t\t\tfor (const cookieString of cookieStrings) {\n\t\t\t\t\t\tconst cookie = Cookie.parse(cookieString)\n\t\t\t\t\t\tif (cookie) {\n\t\t\t\t\t\t\tthis.cookiejar.setCookieSync(cookie, res.config.baseURL)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn res\n\t\t\t})\n\t\t}\n\n\t\tif (cookies) {\n\t\t\tfor (const cookieString of cookies.split(\"; \")) {\n\t\t\t\tconst cookie = Cookie.parse(`${cookieString}`)\n\t\t\t\tif (!cookie) continue\n\n\t\t\t\tthis.cookiejar.setCookieSync(cookie, \"https://www.youtube.com/\")\n\t\t\t}\n\t\t}\n\n\t\tconst html = (await this.client.get(\"/\")).data as string\n\t\tconst setConfigs = html.match(/ytcfg\\.set\\(.*\\)/) || []\n\n\t\tconst configs = setConfigs\n\t\t\t.map(c => c.slice(10, -1))\n\t\t\t.map(s => {\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.parse(s)\n\t\t\t\t} catch {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t})\n\t\t\t.filter(j => !!j)\n\n\t\tfor (const config of configs) {\n\t\t\tthis.config = {\n\t\t\t\t...this.config,\n\t\t\t\t...config,\n\t\t\t}\n\t\t}\n\n\t\tif (!this.config) {\n\t\t\tthis.config = {}\n\t\t}\n\n\t\tif (GL) this.config.GL = GL\n\t\tif (HL) this.config.HL = HL\n\n\t\treturn this\n\t}\n\n\t/**\n\t * Constructs a basic YouTube Music API request with all essential headers\n\t * and body parameters needed to make the API work\n\t *\n\t * @param endpoint Endpoint for the request\n\t * @param body Body\n\t * @param query Search params\n\t * @returns Raw response from YouTube Music API which needs to be parsed\n\t */\n\tprivate async constructRequest(\n\t\tendpoint: string,\n\t\tbody: Record<string, any> = {},\n\t\tquery: Record<string, string> = {},\n\t) {\n\t\tif (!this.config) {\n\t\t\tthrow new Error(\"API not initialized. Make sure to call the initialize() method first\")\n\t\t}\n\n\t\tconst headers: Record<string, any> = {\n\t\t\t...this.client.defaults.headers,\n\t\t\t\"x-origin\": this.client.defaults.baseURL,\n\t\t\t\"X-Goog-Visitor-Id\": this.config.VISITOR_DATA || \"\",\n\t\t\t\"X-YouTube-Client-Name\": this.config.INNERTUBE_CONTEXT_CLIENT_NAME,\n\t\t\t\"X-YouTube-Client-Version\": this.config.INNERTUBE_CLIENT_VERSION,\n\t\t\t\"X-YouTube-Device\": this.config.DEVICE,\n\t\t\t\"X-YouTube-Page-CL\": this.config.PAGE_CL,\n\t\t\t\"X-YouTube-Page-Label\": this.config.PAGE_BUILD_LABEL,\n\t\t\t\"X-YouTube-Utc-Offset\": String(-new Date().getTimezoneOffset()),\n\t\t\t\"X-YouTube-Time-Zone\": new Intl.DateTimeFormat().resolvedOptions().timeZone,\n\t\t}\n\n\t\tconst searchParams = new URLSearchParams({\n\t\t\t...query,\n\t\t\talt: \"json\",\n\t\t\tkey: this.config.INNERTUBE_API_KEY!,\n\t\t})\n\n\t\tconst res = await this.client.post(\n\t\t\t`youtubei/${this.config.INNERTUBE_API_VERSION}/${endpoint}?${searchParams.toString()}`,\n\t\t\t{\n\t\t\t\tcontext: {\n\t\t\t\t\tcapabilities: {},\n\t\t\t\t\tclient: {\n\t\t\t\t\t\tclientName: this.config.INNERTUBE_CLIENT_NAME,\n\t\t\t\t\t\tclientVersion: this.config.INNERTUBE_CLIENT_VERSION,\n\t\t\t\t\t\texperimentIds: [],\n\t\t\t\t\t\texperimentsToken: \"\",\n\t\t\t\t\t\tgl: this.config.GL,\n\t\t\t\t\t\thl: this.config.HL,\n\t\t\t\t\t\tlocationInfo: {\n\t\t\t\t\t\t\tlocationPermissionAuthorizationStatus:\n\t\t\t\t\t\t\t\t\"LOCATION_PERMISSION_AUTHORIZATION_STATUS_UNSUPPORTED\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmusicAppInfo: {\n\t\t\t\t\t\t\tmusicActivityMasterSwitch: \"MUSIC_ACTIVITY_MASTER_SWITCH_INDETERMINATE\",\n\t\t\t\t\t\t\tmusicLocationMasterSwitch: \"MUSIC_LOCATION_MASTER_SWITCH_INDETERMINATE\",\n\t\t\t\t\t\t\tpwaInstallabilityStatus: \"PWA_INSTALLABILITY_STATUS_UNKNOWN\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tutcOffsetMinutes: -new Date().getTimezoneOffset(),\n\t\t\t\t\t},\n\t\t\t\t\trequest: {\n\t\t\t\t\t\tinternalExperimentFlags: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: \"force_music_enable_outertube_tastebuilder_browse\",\n\t\t\t\t\t\t\t\tvalue: \"true\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: \"force_music_enable_outertube_playlist_detail_browse\",\n\t\t\t\t\t\t\t\tvalue: \"true\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: \"force_music_enable_outertube_search_suggestions\",\n\t\t\t\t\t\t\t\tvalue: \"true\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tsessionIndex: {},\n\t\t\t\t\t},\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tenableSafetyMode: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t...body,\n\t\t\t},\n\t\t\t{\n\t\t\t\tresponseType: \"json\",\n\t\t\t\theaders,\n\t\t\t},\n\t\t)\n\n\t\treturn \"responseContext\" in res.data ? res.data : res\n\t}\n\n\t/**\n\t * Get a list of search suggestiong based on the query\n\t *\n\t * @param query Query string\n\t * @returns Search suggestions\n\t */\n\tpublic async getSearchSuggestions(query: string): Promise<string[]> {\n\t\treturn traverseList(\n\t\t\tawait this.constructRequest(\"music/get_search_suggestions\", {\n\t\t\t\tinput: query,\n\t\t\t}),\n\t\t\t\"query\",\n\t\t)\n\t}\n\n\t/**\n\t * Searches YouTube Music API for results\n\t *\n\t * @param query Query string\n\t */\n\tpublic async search(query: string): Promise<SearchResult[]> {\n\t\tconst searchData = await this.constructRequest(\"search\", {\n\t\t\tquery,\n\t\t\tparams: null,\n\t\t})\n\n\t\treturn traverseList(searchData, \"musicResponsiveListItemRenderer\")\n\t\t\t.map(SearchParser.parse)\n\t\t\t.filter(Boolean) as SearchResult[]\n\t}\n\n\t/**\n\t * Searches YouTube Music API for songs\n\t *\n\t * @param query Query string\n\t */\n\tpublic async searchSongs(query: string): Promise<SongDetailed[]> {\n\t\tconst searchData = await this.constructRequest(\"search\", {\n\t\t\tquery,\n\t\t\tparams: \"Eg-KAQwIARAAGAAgACgAMABqChAEEAMQCRAFEAo%3D\",\n\t\t})\n\n\t\treturn traverseList(searchData, \"musicResponsiveListItemRenderer\").map(\n\t\t\tSongParser.parseSearchResult,\n\t\t)\n\t}\n\n\t/**\n\t * Searches YouTube Music API for videos\n\t *\n\t * @param query Query string\n\t */\n\tpublic async searchVideos(query: string): Promise<VideoDetailed[]> {\n\t\tconst searchData = await this.constructRequest(\"search\", {\n\t\t\tquery,\n\t\t\tparams: \"Eg-KAQwIABABGAAgACgAMABqChAEEAMQCRAFEAo%3D\",\n\t\t})\n\n\t\treturn traverseList(searchData, \"musicResponsiveListItemRenderer\").map(\n\t\t\tVideoParser.parseSearchResult,\n\t\t)\n\t}\n\n\t/**\n\t * Searches YouTube Music API for artists\n\t *\n\t * @param query Query string\n\t */\n\tpublic async searchArtists(query: string): Promise<ArtistDetailed[]> {\n\t\tconst searchData = await this.constructRequest(\"search\", {\n\t\t\tquery,\n\t\t\tparams: \"Eg-KAQwIABAAGAAgASgAMABqChAEEAMQCRAFEAo%3D\",\n\t\t})\n\n\t\treturn traverseList(searchData, \"musicResponsiveListItemRenderer\").map(\n\t\t\tArtistParser.parseSearchResult,\n\t\t)\n\t}\n\n\t/**\n\t * Searches YouTube Music API for albums\n\t *\n\t * @param query Query string\n\t */\n\tpublic async searchAlbums(query: string): Promise<AlbumDetailed[]> {\n\t\tconst searchData = await this.constructRequest(\"search\", {\n\t\t\tquery,\n\t\t\tparams: \"Eg-KAQwIABAAGAEgACgAMABqChAEEAMQCRAFEAo%3D\",\n\t\t})\n\n\t\treturn traverseList(searchData, \"musicResponsiveListItemRenderer\").map(\n\t\t\tAlbumParser.parseSearchResult,\n\t\t)\n\t}\n\n\t/**\n\t * Searches YouTube Music API for playlists\n\t *\n\t * @param query Query string\n\t */\n\tpublic async searchPlaylists(query: string): Promise<PlaylistDetailed[]> {\n\t\tconst searchData = await this.constructRequest(\"search\", {\n\t\t\tquery,\n\t\t\tparams: \"Eg-KAQwIABAAGAAgACgBMABqChAEEAMQCRAFEAo%3D\",\n\t\t})\n\n\t\treturn traverseList(searchData, \"musicResponsiveListItemRenderer\").map(\n\t\t\tPlaylistParser.parseSearchResult,\n\t\t)\n\t}\n\n\t/**\n\t * Get all possible information of a Song\n\t *\n\t * @param videoId Video ID\n\t * @returns Song Data\n\t */\n\tpublic async getSong(videoId: string): Promise<SongFull> {\n\t\tif (!videoId.match(/^[a-zA-Z0-9-_]{11}$/)) throw new Error(\"Invalid videoId\")\n\t\tconst data = await this.constructRequest(\"player\", { videoId })\n\n\t\tconst song = SongParser.parse(data)\n\t\tif (song.videoId !== videoId) throw new Error(\"Invalid videoId\")\n\t\treturn song\n\t}\n\t\n /**\n * Get all possible information of a Up Nexts Song\n *\n * @param videoId Video ID\n * @returns Up Nexts Data\n */\n \n async getUpNexts(videoId: string): Promise<UpNextsDetails[]> {\n if (!videoId.match(/^[a-zA-Z0-9-_]{11}$/)) throw new Error(\"Invalid videoId\");\n \n const data = await this.constructRequest(\"next\", { \n videoId, \n playlistId: `RDAMVM${videoId}`, \n isAudioOnly: true \n });\n \n const tabs = data?.contents?.singleColumnMusicWatchNextResultsRenderer?.tabbedRenderer?.watchNextTabbedResultsRenderer?.tabs[0]?.tabRenderer?.content?.musicQueueRenderer?.content?.playlistPanelRenderer?.contents;\n \n if (!tabs) throw new Error(\"Invalid response structure\");\n \n\treturn tabs.slice(1).map((item: any) => {\n const { videoId, title, shortBylineText, lengthText, thumbnail } = item.playlistPanelVideoRenderer;\n return {\n\t\ttype: \"SONG\",\n videoId,\n title: title?.runs[0]?.text || \"Unknown\",\n artists: shortBylineText?.runs[0]?.text || \"Unknown\",\n duration: lengthText?.runs[0]?.text || \"Unknown\",\n thumbnail: thumbnail?.thumbnails.at(-1)?.url || \"Unknown\",\n };\n });\n }\n\n\t/**\n\t * Get all possible information of a Video\n\t *\n\t * @param videoId Video ID\n\t * @returns Video Data\n\t */\n\tpublic async getVideo(videoId: string): Promise<VideoFull> {\n\t\tif (!videoId.match(/^[a-zA-Z0-9-_]{11}$/)) throw new Error(\"Invalid videoId\")\n\t\tconst data = await this.constructRequest(\"player\", { videoId })\n\n\t\tconst video = VideoParser.parse(data)\n\t\tif (video.videoId !== videoId) throw new Error(\"Invalid videoId\")\n\t\treturn video\n\t}\n\n\t/**\n\t * Get lyrics of a specific Song\n\t *\n\t * @param videoId Video ID\n\t * @returns Lyrics\n\t */\n\tpublic async getLyrics(videoId: string) {\n\t\tif (!videoId.match(/^[a-zA-Z0-9-_]{11}$/)) throw new Error(\"Invalid videoId\")\n\t\tconst data = await this.constructRequest(\"next\", { videoId })\n\t\tconst browseId = traverse(traverseList(data, \"tabs\", \"tabRenderer\")[1], \"browseId\")\n\n\t\tconst lyricsData = await this.constructRequest(\"browse\", { browseId })\n\t\tconst lyrics = traverseString(lyricsData, \"description\", \"runs\", \"text\")\n\n\t\treturn lyrics\n\t\t\t? lyrics\n\t\t\t\t\t.replaceAll(\"\\r\", \"\")\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter((v: string) => !!v)\n\t\t\t: null;\n\t}\n\n\t/**\n\t * Get all possible information of an Artist\n\t *\n\t * @param artistId Artist ID\n\t * @returns Artist Data\n\t */\n\tpublic async getArtist(artistId: string): Promise<ArtistFull> {\n\t\tconst data = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: artistId,\n\t\t})\n\n\t\treturn ArtistParser.parse(data, artistId)\n\t}\n\n\t/**\n\t * Get all of Artist's Songs\n\t *\n\t * @param artistId Artist ID\n\t * @returns Artist's Songs\n\t */\n\tpublic async getArtistSongs(artistId: string): Promise<SongDetailed[]> {\n\t\tconst artistData = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: artistId,\n\t\t})\n\t\tconst browseToken = traverse(artistData, \"musicShelfRenderer\", \"title\", \"browseId\")\n\n\t\tif (browseToken instanceof Array) return []\n\n\t\tconst songsData = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: browseToken,\n\t\t})\n\t\tconst continueToken = traverse(songsData, \"continuation\")\n\t\tconst moreSongsData = await this.constructRequest(\n\t\t\t\"browse\",\n\t\t\t{},\n\t\t\t{ continuation: continueToken },\n\t\t)\n\n\t\treturn [\n\t\t\t...traverseList(songsData, \"musicResponsiveListItemRenderer\"),\n\t\t\t...traverseList(moreSongsData, \"musicResponsiveListItemRenderer\"),\n\t\t].map(s =>\n\t\t\tSongParser.parseArtistSong(s, {\n\t\t\t\tartistId,\n\t\t\t\tname: traverseString(artistData, \"header\", \"title\", \"text\"),\n\t\t\t}),\n\t\t)\n\t}\n\n\t/**\n\t * Get all of Artist's Albums\n\t *\n\t * @param artistId Artist ID\n\t * @returns Artist's Albums\n\t */\n\tpublic async getArtistAlbums(artistId: string): Promise<AlbumDetailed[]> {\n\t\tconst artistData = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: artistId,\n\t\t})\n\t\tconst artistAlbumsData = traverseList(artistData, \"musicCarouselShelfRenderer\")[0]\n\t\tconst browseBody = traverse(artistAlbumsData, \"moreContentButton\", \"browseEndpoint\")\n\n\t\tconst albumsData = await this.constructRequest(\"browse\", browseBody)\n\n\t\treturn traverseList(albumsData, \"musicTwoRowItemRenderer\").map(item =>\n\t\t\tAlbumParser.parseArtistAlbum(item, {\n\t\t\t\tartistId,\n\t\t\t\tname: traverseString(albumsData, \"header\", \"runs\", \"text\"),\n\t\t\t}),\n\t\t)\n\t}\n\n\t/**\n\t * Get all possible information of an Album\n\t *\n\t * @param albumId Album ID\n\t * @returns Album Data\n\t */\n\tpublic async getAlbum(albumId: string): Promise<AlbumFull> {\n\t\tconst data = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: albumId,\n\t\t})\n\n\t\treturn AlbumParser.parse(data, albumId)\n\t}\n\n\t/**\n\t * Get all possible information of a Playlist except the tracks\n\t *\n\t * @param playlistId Playlist ID\n\t * @returns Playlist Data\n\t */\n\tpublic async getPlaylist(playlistId: string): Promise<PlaylistFull> {\n\t\tif (playlistId.startsWith(\"PL\")) playlistId = \"VL\" + playlistId\n\t\tconst data = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: playlistId,\n\t\t})\n\n\t\treturn PlaylistParser.parse(data, playlistId)\n\t}\n\n\t/**\n\t * Get all videos in a Playlist\n\t *\n\t * @param playlistId Playlist ID\n\t * @returns Playlist's Videos\n\t */\n\tpublic async getPlaylistVideos(playlistId: string): Promise<VideoDetailed[]> {\n\t\tif (playlistId.startsWith(\"PL\")) playlistId = \"VL\" + playlistId\n\t\tconst playlistData = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: playlistId,\n\t\t})\n\n\t\tconst songs = traverseList(\n\t\t\tplaylistData,\n\t\t\t\"musicPlaylistShelfRenderer\",\n\t\t\t\"musicResponsiveListItemRenderer\",\n\t\t)\n\t\tlet continuation = traverse(playlistData, \"continuation\")\n\t\t// Sometimes it returns array, dunno why\n\t\tif (continuation instanceof Array) {\n\t\t\tcontinuation = continuation[0]\n\t\t}\n\n\t\twhile (!(continuation instanceof Array)) {\n\t\t\tconst songsData = await this.constructRequest(\"browse\", {}, { continuation })\n\t\t\tsongs.push(...traverseList(songsData, \"musicResponsiveListItemRenderer\"))\n\t\t\tcontinuation = traverse(songsData, \"continuation\")\n\t\t}\n\n\t\treturn songs.map(VideoParser.parsePlaylistVideo).filter((video): video is VideoDetailed => video !== undefined)\n\t}\n\n\t/**\n\t * Get sections for the home page.\n\t *\n\t * @returns Mixed HomeSection\n\t */\n\tpublic async getHomeSections(): Promise<HomeSection[]> {\n\t\tconst data = await this.constructRequest(\"browse\", {\n\t\t\tbrowseId: FE_MUSIC_HOME,\n\t\t})\n\n\t\tconst sections = traverseList(\"sectionListRenderer\", \"contents\")\n\t\tlet continuation = traverseString(data, \"continuation\")\n\t\twhile (continuation) {\n\t\t\tconst data = await this.constructRequest(\"browse\", {}, { continuation })\n\t\t\tsections.push(...traverseList(data, \"sectionListContinuation\", \"contents\"))\n\t\t\tcontinuation = traverseString(data, \"continuation\")\n\t\t}\n\n\t\treturn sections.map(Parser.parseHomeSection)\n\t}\n}\n","export enum PageType {\n\tMUSIC_PAGE_TYPE_ALBUM = \"MUSIC_PAGE_TYPE_ALBUM\",\n\tMUSIC_PAGE_TYPE_PLAYLIST = \"MUSIC_PAGE_TYPE_PLAYLIST\",\n\tMUSIC_VIDEO_TYPE_OMV = \"MUSIC_VIDEO_TYPE_OMV\",\n}\n\nexport const FE_MUSIC_HOME = \"FEmusic_home\"\n","import { z } from \"zod\"\n\nexport type ThumbnailFull = z.infer<typeof ThumbnailFull>\nexport const ThumbnailFull = z\n\t.object({\n\t\turl: z.string(),\n\t\twidth: z.number(),\n\t\theight: z.number(),\n\t})\n\t.strict()\n\nexport type ArtistBasic = z.infer<typeof ArtistBasic>\nexport const ArtistBasic = z\n\t.object({\n\t\tartistId: z.nullable(z.string()),\n\t\tname: z.string(),\n\t})\n\t.strict()\n\nexport type AlbumBasic = z.infer<typeof AlbumBasic>\nexport const AlbumBasic = z\n\t.object({\n\t\talbumId: z.string(),\n\t\tname: z.string(),\n\t})\n\t.strict()\n\nexport type SongDetailed = z.infer<typeof SongDetailed>\nexport const SongDetailed = z\n\t.object({\n\t\ttype: z.literal(\"SONG\"),\n\t\tvideoId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\talbum: z.nullable(AlbumBasic),\n\t\tduration: z.nullable(z.number()),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t})\n\t.strict()\n\nexport type VideoDetailed = z.infer<typeof VideoDetailed>\nexport const VideoDetailed = z\n\t.object({\n\t\ttype: z.literal(\"VIDEO\"),\n\t\tvideoId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\tduration: z.nullable(z.number()),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t})\n\t.strict()\n\nexport type ArtistDetailed = z.infer<typeof ArtistDetailed>\nexport const ArtistDetailed = z\n\t.object({\n\t\tartistId: z.string(),\n\t\tname: z.string(),\n\t\ttype: z.literal(\"ARTIST\"),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t})\n\t.strict()\n\nexport type AlbumDetailed = z.infer<typeof AlbumDetailed>\nexport const AlbumDetailed = z\n\t.object({\n\t\ttype: z.literal(\"ALBUM\"),\n\t\talbumId: z.string(),\n\t\tplaylistId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\tyear: z.nullable(z.number()),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t})\n\t.strict()\n\nexport type PlaylistDetailed = z.infer<typeof PlaylistDetailed>\nexport const PlaylistDetailed = z\n\t.object({\n\t\ttype: z.literal(\"PLAYLIST\"),\n\t\tplaylistId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\tthumbnails: z.array(ThumbnailFull),\n\t})\n\t.strict()\n\nexport type SongFull = z.infer<typeof SongFull>\nexport const SongFull = z\n\t.object({\n\t\ttype: z.literal(\"SONG\"),\n\t\tvideoId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\tduration: z.number(),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t\tformats: z.array(z.any()),\n\t\tadaptiveFormats: z.array(z.any()),\n\t})\n\t.strict()\n\nexport type VideoFull = z.infer<typeof VideoFull>\nexport const VideoFull = z\n\t.object({\n\t\ttype: z.literal(\"VIDEO\"),\n\t\tvideoId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\tduration: z.number(),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t\tunlisted: z.boolean(),\n\t\tfamilySafe: z.boolean(),\n\t\tpaid: z.boolean(),\n\t\ttags: z.array(z.string()),\n\t})\n\t.strict()\n\nexport type UpNextsDetails = z.infer<typeof UpNextsDetails>\nexport const UpNextsDetails = z\n\t\t.object({\n\t\ttype: z.literal(\"SONG\"),\n\t\tvideoId: z.string(),\n\t\ttitle: z.string(),\n\t\tartists: ArtistBasic,\n\t\tduration: z.number(),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t\t})\n\t\t.strict()\n\t\t\nexport type ArtistFull = z.infer<typeof ArtistFull>\nexport const ArtistFull = z\n\t.object({\n\t\tartistId: z.string(),\n\t\tname: z.string(),\n\t\ttype: z.literal(\"ARTIST\"),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t\ttopSongs: z.array(SongDetailed),\n\t\ttopAlbums: z.array(AlbumDetailed),\n\t\ttopSingles: z.array(AlbumDetailed),\n\t\ttopVideos: z.array(VideoDetailed),\n\t\tfeaturedOn: z.array(PlaylistDetailed),\n\t\tsimilarArtists: z.array(ArtistDetailed),\n\t})\n\t.strict()\n\nexport type AlbumFull = z.infer<typeof AlbumFull>\nexport const AlbumFull = z\n\t.object({\n\t\ttype: z.literal(\"ALBUM\"),\n\t\talbumId: z.string(),\n\t\tplaylistId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\tyear: z.nullable(z.number()),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t\tsongs: z.array(SongDetailed),\n\t})\n\t.strict()\n\nexport type PlaylistFull = z.infer<typeof PlaylistFull>\nexport const PlaylistFull = z\n\t.object({\n\t\ttype: z.literal(\"PLAYLIST\"),\n\t\tplaylistId: z.string(),\n\t\tname: z.string(),\n\t\tartist: ArtistBasic,\n\t\tvideoCount: z.number(),\n\t\tthumbnails: z.array(ThumbnailFull),\n\t})\n\t.strict()\n\nexport type SearchResult = z.infer<typeof SearchResult>\nexport const SearchResult = z.discriminatedUnion(\"type\", [\n\tSongDetailed,\n\tVideoDetailed,\n\tAlbumDetailed,\n\tArtistDetailed,\n\tPlaylistDetailed,\n])\n\nexport type HomeSection = z.infer<typeof HomeSection>\nexport const HomeSection = z\n\t.object({\n\t\ttitle: z.string(),\n\t\tcontents: z.array(z.union([AlbumDetailed, PlaylistDetailed, SongDetailed])),\n\t})\n\t.strict()\n\nexport type ProxyConfig = z.infer<typeof ProxyConfig>\nexport const ProxyConfig = z\n\t.object({\n\t\tprotocol: z.enum([\"http\", \"https\", \"socks4\", \"socks5\"]).optional(),\n\t\thost: z.string(),\n\t\tport: z.number(),\n\t\tauth: z\n\t\t\t.object({\n\t\t\t\tusername: z.string(),\n\t\t\t\tpassword: z.string(),\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t.strict()\n\nexport type YTMusicOptions = z.infer<typeof YTMusicOptions>\nexport const YTMusicOptions = z\n\t.object({\n\t\tcookies: z.string().optional(),\n\t\tGL: z.string().optional(),\n\t\tHL: z.string().optional(),\n\t\tproxy: ProxyConfig.optional(),\n\t})\n\t.strict()\n","export const ignoreOverride = Symbol(\"Let zodToJsonSchema decide on which parser to use\");\nexport const jsonDescription = (jsonSchema, def) => {\n if (def.description) {\n try {\n return {\n ...jsonSchema,\n ...JSON.parse(def.description),\n };\n }\n catch { }\n }\n return jsonSchema;\n};\nexport const defaultOptions = {\n name: undefined,\n $refStrategy: \"root\",\n basePath: [\"#\"],\n effectStrategy: \"input\",\n pipeStrategy: \"all\",\n dateStrategy: \"format:date-time\",\n mapStrategy: \"entries\",\n removeAdditionalStrategy: \"passthrough\",\n allowedAdditionalProperties: true,\n rejectedAdditionalProperties: false,\n definitionPath: \"definitions\",\n target: \"jsonSchema7\",\n strictUnions: false,\n definitions: {},\n errorMessages: false,\n markdownDescription: false,\n patternStrategy: \"escape\",\n applyRegexFlags: false,\n emailStrategy: \"format:email\",\n base64Strategy: \"contentEncoding:base64\",\n nameStrategy: \"ref\",\n openAiAnyTypeName: \"OpenAiAnyType\"\n};\nexport const getDefaultOptions = (options) => (typeof options === \"string\"\n ? {\n ...defaultOptions,\n name: options,\n }\n : {\n ...defaultOptions,\n ...options,\n });\n","import { getDefaultOptions } from \"./Options.js\";\nexport const getRefs = (options) => {\n const _options = getDefaultOptions(options);\n const currentPath = _options.name !== undefined\n ? [..._options.basePath, _options.definitionPath, _options.name]\n : _options.basePath;\n return {\n ..._options,\n flags: { hasReferencedOpenAiAnyType: false },\n currentPath: currentPath,\n propertyPath: undefined,\n seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [\n def._def,\n {\n def: def._def,\n path: [..._options.basePath, _options.definitionPath, name],\n // Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.\n jsonSchema: undefined,\n },\n ])),\n };\n};\n","export function addErrorMessage(res, key, errorMessage, refs) {\n if (!refs?.errorMessages)\n return;\n if (errorMessage) {\n res.errorMessage = {\n ...res.errorMessage,\n [key]: errorMessage,\n };\n }\n}\nexport function setResponseValueAndErrors(res, key, value, errorMessage, refs) {\n res[key] = value;\n addErrorMessage(res, key, errorMessage, refs);\n}\n","export const getRelativePath = (pathA, pathB) => {\n let i = 0;\n for (; i < pathA.length && i < pathB.length; i++) {\n if (pathA[i] !== pathB[i])\n break;\n }\n return [(pathA.length - i).toString(), ...pathB.slice(i)].join(\"/\");\n};\n","import { ZodFirstPartyTypeKind } from \"zod\";\nimport { parseAnyDef } from \"./parsers/any.js\";\nimport { parseArrayDef } from \"./parsers/array.js\";\nimport { parseBigintDef } from \"./parsers/bigint.js\";\nimport { parseBooleanDef } from \"./parsers/boolean.js\";\nimport { parseBrandedDef } from \"./parsers/branded.js\";\nimport { parseCatchDef } from \"./parsers/catch.js\";\nimport { parseDateDef } from \"./parsers/date.js\";\nimport { parseDefaultDef } from \"./parsers/default.js\";\nimport { parseEffectsDef } from \"./parsers/effects.js\";\nimport { parseEnumDef } from \"./parsers/enum.js\";\nimport { parseIntersectionDef } from \"./parsers/intersection.js\";\nimport { parseLiteralDef } from \"./parsers/literal.js\";\nimport { parseMapDef } from \"./parsers/map.js\";\nimport { parseNativeEnumDef } from \"./parsers/nativeEnum.js\";\nimport { parseNeverDef } from \"./parsers/never.js\";\nimport { parseNullDef } from \"./parsers/null.js\";\nimport { parseNullableDef } from \"./parsers/nullable.js\";\nimport { parseNumberDef } from \"./parsers/number.js\";\nimport { parseObjectDef } from \"./parsers/object.js\";\nimport { parseOptionalDef } from \"./parsers/optional.js\";\nimport { parsePipelineDef } from \"./parsers/pipeline.js\";\nimport { parsePromiseDef } from \"./parsers/promise.js\";\nimport { parseRecordDef } from \"./parsers/record.js\";\nimport { parseSetDef } from \"./parsers/set.js\";\nimport { parseStringDef } from \"./parsers/string.js\";\nimport { parseTupleDef } from \"./parsers/tuple.js\";\nimport { parseUndefinedDef } from \"./parsers/undefined.js\";\nimport { parseUnionDef } from \"./parsers/union.js\";\nimport { parseUnknownDef } from \"./parsers/unknown.js\";\nimport { parseReadonlyDef } from \"./parsers/readonly.js\";\nexport const selectParser = (def, typeName, refs) => {\n switch (typeName) {\n case ZodFirstPartyTypeKind.ZodString:\n return parseStringDef(def, refs);\n case ZodFirstPartyTypeKind.ZodNumber:\n return parseNumberDef(def, refs);\n case ZodFirstPartyTypeKind.ZodObject:\n return parseObjectDef(def, refs);\n case ZodFirstPartyTypeKind.ZodBigInt:\n return parseBigintDef(def, refs);\n case ZodFirstPartyTypeKind.ZodBoolean:\n return parseBooleanDef();\n case ZodFirstPartyTypeKind.ZodDate:\n return parseDateDef(def, refs);\n case ZodFirstPartyTypeKind.ZodUndefined:\n return parseUndefinedDef(refs);\n case ZodFirstPartyTypeKind.ZodNull:\n return parseNullDef(refs);\n case ZodFirstPartyTypeKind.ZodArray:\n return parseArrayDef(def, refs);\n case ZodFirstPartyTypeKind.ZodUnion:\n case ZodFirstPartyTypeKind.ZodDiscriminatedUnion:\n return parseUnionDef(def, refs);\n case ZodFirstPartyTypeKind.ZodIntersection:\n return parseIntersectionDef(def, refs);\n case ZodFirstPartyTypeKind.ZodTuple:\n return parseTupleDef(def, refs);\n case ZodFirstPartyTypeKind.ZodRecord:\n return parseRecordDef(def, refs);\n case ZodFirstPartyTypeKind.ZodLiteral:\n return parseLiteralDef(def, refs);\n case ZodFirstPartyTypeKind.ZodEnum:\n return parseEnumDef(def);\n case ZodFirstPartyTypeKind.ZodNativeEnum:\n return parseNativeEnumDef(def);\n case ZodFirstPartyTypeKind.ZodNullable:\n return parseNullableDef(def, refs);\n case ZodFirstPartyTypeKind.ZodOptional:\n return parseOptionalDef(def, refs);\n case ZodFirstPartyTypeKind.ZodMap:\n return parseMapDef(def, refs);\n case ZodFirstPartyTypeKind.ZodSet:\n return parseSetDef(def, refs);\n case ZodFirstPartyTypeKind.ZodLazy:\n return () => def.getter()._def;\n case ZodFirstPartyTypeKind.ZodPromise:\n return parsePromiseDef(def, refs);\n case ZodFirstPartyTypeKind.ZodNaN:\n case ZodFirstPartyTypeKind.ZodNever:\n return parseNeverDef(refs);\n case ZodFirstPartyTypeKind.ZodEffects:\n return parseEffectsDef(def, refs);\n case ZodFirstPartyTypeKind.ZodAny:\n return parseAnyDef(refs);\n case ZodFirstPartyTypeKind.ZodUnknown:\n return parseUnknownDef(refs);\n case ZodFirstPartyTypeKind.ZodDefault:\n return parseDefaultDef(def, refs);\n case ZodFirstPartyTypeKind.ZodBranded:\n return parseBrandedDef(def, refs);\n case ZodFirstPartyTypeKind.ZodReadonly:\n return parseReadonlyDef(def, refs);\n case ZodFirstPartyTypeKind.ZodCatch:\n return parseCatchDef(def, refs);\n case ZodFirstPartyTypeKind.ZodPipeline:\n return parsePipelineDef(def, refs);\n case ZodFirstPartyTypeKind.ZodFunction:\n case ZodFirstPartyTypeKind.ZodVoid:\n case ZodFirstPartyTypeKind.ZodSymbol:\n return undefined;\n default:\n /* c8 ignore next */\n return ((_) => undefined)(typeName);\n }\n};\n","import { getRelativePath } from \"../getRelativePath.js\";\nexport function parseAnyDef(refs) {\n if (refs.target !== \"openAi\") {\n return {};\n }\n const anyDefinitionPath = [\n ...refs.basePath,\n refs.definitionPath,\n refs.openAiAnyTypeName,\n ];\n refs.flags.hasReferencedOpenAiAnyType = true;\n return {\n $ref: refs.$refStrategy === \"relative\"\n ? getRelativePath(anyDefinitionPath, refs.currentPath)\n : anyDefinitionPath.join(\"/\"),\n };\n}\n","import { ZodFirstPartyTypeKind } from \"zod\";\nimport { setResponseValueAndErrors } from \"../errorMessages.js\";\nimport { parseDef } from \"../parseDef.js\";\nexport function parseArrayDef(def, refs) {\n const res = {\n type: \"array\",\n };\n if (def.type?._def &&\n def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) {\n res.items = parseDef(def.type._def, {\n ...refs,\n currentPath: [...refs.currentPath, \"items\"],\n });\n }\n if (def.minLength) {\n setResponseValueAndErrors(res, \"minItems\", def.minLength.value, def.minLength.message, refs);\n }\n if (def.maxLength) {\n setResponseValueAndErrors(res, \"maxItems\", def.maxLength.value, def.maxLength.message, refs);\n }\n if (def.exactLength) {\n setResponseValueAndErrors(res, \"minItems\", def.exactLength.value, def.exactLength.message, refs);\n setResponseValueAndErrors(res, \"maxItems\", def.exactLength.value, def.exactLength.message, refs);\n }\n return res;\n}\n","import { setResponseValueAndErrors } from \"../errorMessages.js\";\nexport function parseBigintDef(def, refs) {\n const res = {\n type: \"integer\",\n format: \"int64\",\n };\n if (!def.checks)\n return res;\n for (const check of def.checks) {\n switch (check.kind) {\n case \"min\":\n if (refs.target === \"jsonSchema7\") {\n if (check.inclusive) {\n setResponseValueAndErrors(res, \"minimum\", check.value, check.message, refs);\n }\n else {\n setResponseValueAndErrors(res, \"exclusiveMinimum\", check.value, check.message, refs);\n }\n }\n else {\n if (!check.inclusive) {\n res.exclusiveMinimum = true;\n }\n setResponseValueAndErrors(res, \"minimum\", check.value, check.message, refs);\n }\n break;\n case \"max\":\n if (refs.target === \"jsonSchema7\") {\n if (check.inclusive) {\n setResponseValueAndErrors(res, \"maximum\", check.value, check.message, refs);\n }\n else {\n setResponseValueAndErrors(res, \"exclusiveMaximum\", check.value, check.message, refs);\n }\n }\n else {\n if (!check.inclusive) {\n res.exclusiveMaximum = true;\n }\n setResponseValueAndErrors(res, \"maximum\", check.value, check.message, refs);\n }\n break;\n case \"multipleOf\":\n setResponseValueAndErrors(res, \"multipleOf\", check.value, check.message, refs);\n break;\n }\n }\n return res;\n}\n","export function parseBooleanDef() {\n return {\n type: \"boolean\",\n };\n}\n","import { parseDef } from \"../parseDef.js\";\nexport function parseBrandedDef(_def, refs) {\n return parseDef(_def.type._def, refs);\n}\n","import { parseDef } from \"../parseDef.js\";\nexport const parseCatchDef = (def, refs) => {\n return parseDef(def.innerType._def, refs);\n};\n","import { setResponseValueAndErrors } from \"../errorMessages.js\";\nexport function parseDateDef(def, refs, overrideDateStrategy) {\n const strategy = overrideDateStrategy ?? refs.dateStrategy;\n if (Array.isArray(strategy)) {\n return {\n anyOf: strategy.map((item, i) => parseDateDef(def, refs, item)),\n };\n }\n switch (strategy) {\n case \"string\":\n case \"format:date-time\":\n return {\n type: \"string\",\n format: \"date-time\",\n };\n case \"format:date\":\n return {\n type: \"string\",\n format: \"date\",\n };\n case \"integer\":\n return integerDateParser(def, refs);\n }\n}\nconst integerDateParser = (def, refs) => {\n const res = {\n type: \"integer\",\n format: \"unix-time\",\n };\n if (refs.target === \"openApi3\") {\n return res;\n }\n for (const check of def.checks) {\n switch (check.kind) {\n case \"min\":\n setResponseValueAndErrors(res, \"minimum\", check.value, // This is in milliseconds\n check.message, refs);\n break;\n case \"max\":\n setResponseValueAndErrors(res, \"maximum\", check.value, // This is in milliseconds\n check.message, refs);\n break;\n }\n }\n return res;\n};\n","import { parseDef } from \"../parseDef.js\";\nexport function parseDefaultDef(_def, refs) {\n return {\n ...parseDef(_def.innerType._def, refs),\n default: _def.defaultValue(),\n };\n}\n","import { parseDef } from \"../parseDef.js\";\nimport { parseAnyDef } from \"./any.js\";\nexport function parseEffectsDef(_def, refs) {\n return refs.effectStrategy === \"input\"\n ? parseDef(_def.schema._def, refs)\n : parseAnyDef(refs);\n}\n","export function parseEnumDef(def) {\n return {\n type: \"string\",\n enum: Array.from(def.values),\n };\n}\n","import { parseDef } from \"../parseDef.js\";\nconst isJsonSchema7AllOfType = (type) => {\n if (\"type\" in type && type.type === \"string\")\n return false;\n return \"allOf\" in type;\n};\nexport function parseIntersectionDef(def, refs) {\n const allOf = [\n parseDef(def.left._def, {\n ...refs,\n currentPath: [...refs.currentPath, \"allOf\", \"0\"],\n }),\n parseDef(def.right._def, {\n ...refs,\n currentPath: [...refs.currentPath, \"allOf\", \"1\"],\n }),\n ].filter((x) => !!x);\n let unevaluatedProperties = refs.target === \"jsonSchema2019-09\"\n ? { unevaluatedProperties: false }\n : undefined;\n const mergedAllOf = [];\n // If either of the schemas is an allOf, merge them into a single allOf\n allOf.forEach((schema) => {\n if (isJsonSchema7AllOfType(schema)) {\n mergedAllOf.push(...schema.allOf);\n if (schema.unevaluatedProperties === undefined) {\n // If one of the schemas has no unevaluatedProperties set,\n // the merged schema should also have no unevaluatedProperties set\n unevaluatedProperties = undefined;\n }\n }\n else {\n let nestedSchema = schema;\n if (\"additionalProperties\" in schema &&\n schema.additionalProperties === false) {\n const { additionalProperties, ...rest } = schema;\n nestedSchema = rest;\n }\n else {\n // As soon as one of the schemas has additionalProperties set not to false, we allow unevaluatedProperties\n unevaluatedProperties = undefined;\n }\n mergedAllOf.push(nestedSchema);\n }\n });\n return mergedAllOf.length\n ? {\n allOf: mergedAllOf,\n ...unevaluatedProperties,\n }\n : undefined;\n}\n","export function parseLiteralDef(def, refs) {\n const parsedType = typeof def.value;\n if (parsedType !== \"bigint\" &&\n parsedType !== \"number\" &&\n parsedType !== \"boolean\" &&\n parsedType !== \"string\") {\n return {\n type: Array.isArray(def.value) ? \"array\" : \"object\",\n };\n }\n if (refs.target === \"openApi3\") {\n return {\n type: parsedType === \"bigint\" ? \"integer\" : parsedType,\n enum: [def.value],\n };\n }\n return {\n type: parsedType === \"bigint\" ? \"integer\" : parsedType,\n const: def.value,\n };\n}\n","import { ZodFirstPartyTypeKind, } from \"zod\";\nimport { parseDef } from \"../parseDef.js\";\nimport { parseStringDef } from \"./string.js\";\nimport { parseBrandedDef } from \"./branded.js\";\nimport { parseAnyDef } from \"./any.js\";\nexport function parseRecordDef(def, refs) {\n if (refs.target === \"openAi\") {\n console.warn(\"Warning: OpenAI may not support records in schemas! Try an array of key-value pairs instead.\");\n }\n if (refs.target === \"openApi3\" &&\n def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {\n return {\n type: \"object\",\n required: def.keyType._def.values,\n properties: def.keyType._def.values.reduce((acc, key) => ({\n ...acc,\n [key]: parseDef(def.valueType._def, {\n ...refs,\n currentPath: [...refs.currentPath, \"properties\", key],\n }) ?? parseAnyDef(refs),\n }), {}),\n additionalProperties: refs.rejectedAdditionalProperties,\n };\n }\n const schema = {\n type: \"object\",\n additionalProperties: parseDef(def.valueType._def, {\n ...refs,\n currentPath: [...refs.currentPath, \"additionalProperties\"],\n }) ?? refs.allowedAdditionalProperties,\n };\n if (refs.target === \"openApi3\") {\n return schema;\n }\n if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodString &&\n def.keyType._def.checks?.length) {\n const { type, ...keyType } = parseStringDef(def.keyType._def, refs);\n return {\n ...schema,\n propertyNames: keyType,\n };\n }\n else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {\n return {\n ...schema,\n propertyNames: {\n enum: def.keyType._def.values,\n },\n };\n }\n else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodBranded &&\n def.keyType._def.type._def.typeName === ZodFirstPartyTypeKind.ZodString &&\n def.keyType._def.type._def.checks?.length) {\n const { type, ...keyType } = parseBrandedDef(def.keyType._def, refs);\n return {\n ...schema,\n propertyNames: keyType,\n };\n }\n return schema;\n}\n","import { setResponseValueAndErrors } from \"../errorMessages.js\";\nlet emojiRegex = undefined;\n/**\n * Generated from the regular expressions found here as of 2024-05-22:\n * https://github.com/colinhacks/zod/blob/master/src/types.ts.\n *\n * Expressions with /i flag have been changed accordingly.\n */\nexport const zodPatterns = {\n /**\n * `c` was changed to `[cC]` to replicate /i flag\n */\n cuid: /^[cC][^\\s-]{8,}$/,\n cuid2: /^[0-9a-z]+$/,\n ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,\n /**\n * `a-z` was added to replicate /i flag\n */\n email: /^(?!\\.)(?!.*\\.\\.)([a-zA-Z0-9_'+\\-\\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+[a-zA-Z]{2,}$/,\n /**\n * Constructed a valid Unicode RegExp\n *\n * Lazily instantiate since this type of regex isn't supported\n * in all envs (e.g. React Native).\n *\n * See:\n * https://github.com/colinhacks/zod/issues/2433\n * Fix in Zod:\n * https://github.com/colinhacks/zod/commit/9340fd51e48576a75adc919bff65dbc4a5d4c99b\n */\n emoji: () => {\n if (emojiRegex === undefined) {\n emojiRegex = RegExp(\"^(\\\\p{Extended_Pictographic}|\\\\p{Emoji_Component})+$\", \"u\");\n }\n return emojiRegex;\n },\n /**\n * Unused\n */\n uuid: /^[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}$/,\n /**\n * Unused\n */\n ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,\n ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/(3[0-2]|[12]?[0-9])$/,\n /**\n * Unused\n */\n ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{